¿Cómo diseñar una tabla de base de datos de relaciones para almacenar una relación de amistad?


9

Quiero diseñar una mesa para almacenar la relación de amistad en mi proyecto web

Debe cumplir al menos las siguientes 4 condiciones:

quién envía la solicitud de agregar amigo, por ejemplo (si A A B, entonces esta columna será A)

quien recibe la solicitud de agregar amigo, por ejemplo (si A TO B, entonces esta columna será B)

estado actual, por ejemplo (0 denota rechazado mientras que 1 denota aceptado o 2 denota no procesado

nuestra relación de amistad es bilateral

Si alguno de ustedes tiene experiencia con esto, cualquier sugerencia es bienvenida

mi diseño actual (creo que está mal ahora) es así, estas son las columnas

frienshipId  
fromUserId  
toUserId  
status  
requestTime

¿Puedo sugerirle que use la vista de código (resalte su texto y presione ctrl-k o ponga cuatro espacios antes de cada línea) y resalte su DDL para que podamos ver cómo está diseñado su modelo de datos (o cómo desea diseñarlo)
jcolebrand

Consulte también la discusión aquí: stackoverflow.com/questions/10807900/…
Flo

Usa una base de datos gráfica. Estos están diseñados solo para estas circunstancias.
Michael Green

Respuestas:


9

Crearía una tabla muy parecida a la que tienes. Estoy usando los tipos de datos y la sintaxis de SQL Server, es posible que deba ajustarlos según su plataforma.

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

La indexación de la tabla será crítica a medida que la tabla crezca a decenas y cientos de millones.


¿Qué pasa con un índice agrupado / clave primaria en StatusId?
bernd_k

Se solucionó el problema del nombre duplicado. El índice agrupado debe estar en FriendStatusId. La clave principal podría ser FriendStatusId o una combinación de FromUserId y ToUserId.
mrdenny

Aunque si permite múltiples solicitudes de amistad, querrá la PK en FromUserID, ToUserId, SentTime o el Clustered Index.
mrdenny

su estrategia de nombres es mejor ...
Hola

8

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

Para enumerar amistades, una vista:

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;

Puedes usarlo así:

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

¿Qué te hace pensar que tu diseño actual es malo? Aquí hay una tabla de creación para 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 datos es Oracle, es posible que desee considerar una columna virtual indexada que limitará los datos a las entradas necesarias para consultas particulares. Por ejemplo, podría tener una columna virtual llamada AcceptedFromUserId que usa la función DECODE (StatusId, 1, FromUserId, NULL). El índice solo contendría AcceptedUserIds y, por lo tanto, sería más pequeño que un índice para todos los UserIds. Si limpia regularmente las solicitudes rechazadas, una columna virtual indexada en PendingToUserId podría ser más útil.

Una alternativa si tuviera particiones sería particionar la tabla en el StatusId.

Si no necesita múltiples solicitudes de amistad entre los mismos usuarios al mismo tiempo, puede abandonar FriendId usando FromUserId, ToUserId y StatusId como su clave principal. En este caso, también debe considerar hacer de la tabla una Tabla organizada de índice.


-2

Esquema:

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
)

De PHP:

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

¿Y qué hacer con la mutualidad? (Y la friendsdefinición de la tabla es sospechosa de error de sintaxis)
Dezso
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.