友情関係を格納するための関係データベーステーブルを設計する方法


9

Webプロジェクトに友情関係を格納するテーブルを設計したい

少なくとも次の4つの条件を満たす必要があります。

友達追加リクエストを送信したユーザー(例:A TO Bの場合、この列はAになります)

友達追加リクエストを受け取ったユーザー(例:A TO Bの場合、この列はBになります)

現在のステータスeg(0は拒否を示しますが、1は受け入れ済み、2は未処理を示します

私たちの友人関係は二国間です

あなたがこれを経験したことがあれば、どんな提案も歓迎します

私の現在の設計は、(私は今、悪い右を考えて)このようなもので 、これらは列です

frienshipId  
fromUserId  
toUserId  
status  
requestTime

コードビュー(テキストを強調表示してctrl-kを押すか、各行の前に4つのスペースを置く)を使用してDDLを強調表示し、データモデルの設計方法(または設計方法)を確認できますか
jcolebrand

また、ここでの議論をチェック:stackoverflow.com/questions/10807900/...
Floの

グラフデータベースを使用します。これらは、まさにこの状況のた​​めに設計されています。
マイケルグリーン

回答:


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

名前の重複の問題を修正しました。クラスタ化インデックスはFriendStatusIdにある必要があります。主キーは、FriendStatusIdまたはFromUserIdとToUserIdの組み合わせにすることができます。
mrdenny、2011年

ただし、複数のフレンド要求を許可する場合は、FromUserID、ToUserId、SentTime、またはクラスター化インデックスのPKが必要になります。
mrdenny、2011年

あなたの命名戦略はより良いです...
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の場合、データを特定のクエリに必要なエントリに制限するインデックス付き仮想列を検討することをお勧めします。たとえば、関数DECODE(StatusId、1、FromUserId、NULL)を使用するAcceptedFromUserIdという仮想列があるとします。インデックスにはAcceptedUserIdsのみが含まれるため、すべてのUserIdsのインデックスよりも小さくなります。拒否された要求を定期的に一掃する場合は、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.