如何设计一个关系数据库表来存储友谊关系?


9

我想设计一个表来存储我的Web项目中的友谊关系

它至少应满足以下四个条件:

发送添加好友请求的人,例如(如果从A到B,则此列为A)

谁收到添加朋友的请求,例如(如果从A到B,则此列为B)

当前状态,例如(0表示拒绝,1表示接受,2表示未处理

我们的朋友关系是双边的

如果您有任何经验,欢迎任何建议

我当前的设计(我认为现在很糟糕)是这样的, 这些是专栏

frienshipId  
fromUserId  
toUserId  
status  
requestTime

我可以建议使用代码视图(突出显示文本并按ctrl-k或在每行之前放置四个空格)并突出显示DDL,以便我们可以看到您的数据模型是如何设计的(或您想如何设计的)
jcolebrand

而且,这里检查的讨论:stackoverflow.com/questions/10807900/...
弗洛

使用图形数据库。这些仅用于这种情况。
Michael Green

Answers:


9

我会创建一个非常类似于您所拥有的表的表。我正在使用SQL Server数据类型和语法,您可能需要根据平台进行调整。

CREATE TABLE FriendStatus
(FriendStatusId BIGINT PRIMARY KEY IDENTITY(1,1),
FromUserId BIGINT,
ToUserId BIGINT,
StatusId TINYINT,
SentTime DATETIME2,
ResponseTime DATETIME2);

随着表增长到数千万,表的索引编制将变得至关重要。


关于StatusId的聚集索引/主键呢?
bernd_k 2011年

修复了重复名称的问题。聚簇索引应该在FriendStatusId上。主键可以是FriendStatusId或FromUserId和ToUserId的组合。
mrdenny

尽管如果允许多个朋友请求,则需要在FromUserID,ToUserId,SentTime或聚集索引上进行PK。
mrdenny

您的命名策略更好...
Hi福气鱼

8

在PostgreSQL上:

CREATE TABLE users (
    users_id serial PRIMARY KEY,
    name text UNIQUE NOT NULL
);

CREATE TABLE friends (
    friends_id serial PRIMARY KEY,
    timestamp TIMESTAMPTZ default now(),
    user_a integer NOT NULL REFERENCES users,
    user_b integer NOT NULL REFERENCES users,
    status integer NOT NULL default 2
)

要列出友谊,请查看:

CREATE VIEW friendships AS
    SELECT DISTINCT user_a, user_b FROM friends WHERE status = 1
    UNION
    SELECT DISTINCT user_b, user_a FROM friends WHERE status = 1;

您可以这样使用它:

INSERT INTO users ( name ) VALUES ( 'foo' );
INSERT INTO users ( name ) VALUES ( 'bar' );
INSERT INTO users ( name ) VALUES ( 'baz' );

SELECT * FROM users;
 users_id | name 
----------+------
        1 | foo
        2 | bar
        3 | baz

INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 1, 2, 1 );
INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 2, 1, 1 );
INSERT INTO FRIENDS ( user_a, user_b, status ) VALUES ( 1, 3, 1 );

SELECT * FROM friendships ORDER BY user_a, user_b;
 user_a | user_b 
--------+--------
      1 |      2
      1 |      3
      2 |      1
      3 |      1

SELECT a.name, b.name
    FROM friendships
    JOIN users a ON a.users_id = user_a
    JOIN users b ON b.users_id = user_b
    ORDER BY a.name, b.name;
 name | name 
------+------
 bar  | foo
 baz  | foo
 foo  | bar
 foo  | baz

3

是什么让您认为您当前的设计不好?这是Oracle的创建表:

CREATE TABLE IVR.FRIEND (
     FRIENDID   NUMBER(7) NOT NULL 
   , FROMUSERID NUMBER(7) NOT NULL 
   , TOUSERID   NUMBER(7) NOT NULL 
   , STATUSID   NUMBER(2) NOT NULL
   , REQUESTED  DATE      NOT NULL 
   , CONSTRAINT FRIEND_PK PRIMARY KEY (FRIENDID) ENABLE 
);
CREATE SEQUENCE FRIENDIDSEQ;

如果数据库是Oracle,则可能需要考虑建立索引的虚拟列,该列会将数据限制为特定查询所需的条目。例如,您可能有一个名为AcceptedFromUserId的虚拟列,该列使用函数DECODE(StatusId,1,FromUserId,NULL)。该索引将仅包含AcceptedUserIds,因此将小于所有UserId的索引。如果您定期清除拒绝的请求,则在PendingToUserId上建立索引的虚拟列可能会更有用。

如果要进行分区,则另一种方法是对StatusId上的表进行分区。

如果您不需要同时在同一用户之间进行多个好友请求,则可以使用FromUserId,ToUserId和StatusId作为主键来放弃FriendId。在这种情况下,您还应该考虑使该表成为索引组织表。


-2

架构:

CREATE TABLE users (
    users_id serial PRIMARY KEY,
    name text UNIQUE NOT NULL
);

CREATE TABLE friends (
    friends_id serial PRIMARY KEY,
    timestamp TIMESTAMPTZ default now(),
    user_a integer NOT NULL REFERENCES users,
    user_b integer NOT NULL REFERENCES users,
    status integer NOT NULL default 2
)

从PHP:

select * 
from friends 
where user_a=$myid or user_b=$myid

和相互关系如何?(并且该friends表定义存在语法错误。)
dezso 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.