web-dev-qa-db-fra.com

Comment concevoir une table de base de données relationnelle pour stocker la relation d'amitié?

Je veux concevoir une table pour stocker la relation d'amitié dans mon projet Web

Il devrait satisfaire au moins les 4 conditions suivantes:

qui envoie la demande d'add-amitié par ex. (Si A à B alors cette colonne sera a)

qui reçoivent la demande d'add-ami par ex. (Si A à B alors cette colonne sera b)

statut actuel E.G. (0 dénote rejeté alors que 1 dénote accepté ou 2 dénote non transformé

notre relation d'ami est bilatérale

Si l'un de vous est expérimenté avec cela, toute suggestion est accueillie

Mon design actuel (je pense que mal maintenant) est comme çace sont les colonnes

frienshipId  
fromUserId  
toUserId  
status  
requestTime
9
Hi福气鱼

Je créerais une table beaucoup comme celle que vous avez. J'utilise les types de données SQL Server et Syntaxe, vous devrez peut-être modifier en fonction de votre plate-forme.

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

L'indexation de la table sera essentielle car la table augmente aux dizaines et à des centaines de millions.

9
mrdenny

Sur 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
)

Pour la liste des amitiés, une vue:

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;

Vous pouvez l'utiliser comme si:

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
8
jkj

Qu'est-ce qui vous fait penser que votre design actuel est mauvais? Voici une table de création pour 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;

Si la base de données est Oracle, vous pouvez envisager une colonne virtuelle indexée qui limitera les données aux entrées nécessaires à des requêtes particulières. Par exemple, vous pouvez avoir une colonne virtuelle appelée acceptéeFromuserID qui utilise le décodage de fonction (StatutId, 1, Fromuserid, NULL). L'index ne contiendrait que des acomptesserids et serait donc plus petit qu'un index pour tous les ID utilisateur. Si vous nettoyez régulièrement des demandes rejetées, une colonne virtuelle indexée sur PenderTousserID peut être plus utile.

Une alternative si vous aviez un partitionnement serait de partitionner la table sur le statutId.

Si vous n'avez pas besoin de plusieurs demandes d'amis entre les mêmes utilisateurs en même temps, vous pouvez abandonner l'amiide ​​à l'aide de FromUserID, TOUSEERID et StatutID comme clé primaire. Dans ce cas, vous devriez également envisager de faire le tableau une table organisée index.

3
Leigh Riffel