双滴グラフを構成するSQL

id、user_id1、およびuser_id2の列を持つテーブルが必要です。

基本的にこれは、user1がuser2と友好関係にあり、その逆であることを表すリンクを友人グラフに再現します。

私のセットアップは、1人のユーザーとその友人のリストを取得します。私はテーブルに余分なエントリを持っていないと思うので、私はこれをどのようにshoudl扱いますか?

I want to do something like: insert into friendship (user_id1, user_id2) values (, ) where ...

しかし、私はSQLのような条件付きロジックをどのように行うのか分からない

1
両方。最高のアーキテクチャを見つけようとしています。
追加された 著者 lollercoaster,
重複を防ぐ方法を尋ねていますか、特定のユーザーのすべての友人を取得する方法を尋ねていますか?
追加された 著者 a_horse_with_no_name,

4 答え

「論理的に」同じ組み合わせを挿入するのを防ぐために、一意のインデックスを作成することができます。

 CREATE UNIQUE INDEX unique_pair 
      ON your_table (least(user_id1, user_id2), greatest(user_id1, user_id2));

これは標準のANSI SQLであり、ほとんどのDBMSで動作するはずです。 DBMSが leastmaximum をサポートしていない場合は、コンパクトではなく、 CASE

どのように機能するのですか?

(2,1)(1,2)の両方のタプルは常にとして索引付けされます>(1,2) - 残りの部分は UNIQUE で処理されます。

4
追加された
うーん。私はMySQLを使用していると述べたはずです。 #1064 - SQL構文にエラーがあります。指定したunique_pairインデックスソリューションを使用しようとすると、右側の構文が「fb_id1、fb_id2」、「最大(fb_id1、fb_id2))」行1の付近で使用するMySQLサーバーのバージョンに対応するマニュアルをチェックしてください。 ..
追加された 著者 lollercoaster,
面白い! (13、10)のようなペアを挿入しようとするとどうなりますか?そのようなエラーをキャッチする方法はありますか?また、私が正しく理解していれば、このユニークなインデックスはテーブルへの挿入に関する制約として機能していますか?
追加された 著者 lollercoaster,
いいえ、MySQLでは動作しません。他のほとんどのDBMSのような機能インデックスはサポートしていません。
追加された 著者 a_horse_with_no_name,
これはCHECK制約の興味深い代替案であり、MySQLでも動作するはずです。
追加された 著者 mu is too short,
しかし、RAISEのトリガーと自作の実装でCHECK制約を偽ることができます( blogs.oracle.com/svetasmirnova/entry/how_to_raise_error_in )‌、恐ろしい混乱のビットが動作するだろう。
追加された 著者 mu is too short,
この場合、(13,10)を加算することは誤りではない。それはそれを追加し、(10,13)のインデックスを作成するだけです。次に、後で(10,13)を追加しようとすると、そのインデックスも(10,13)となり、そのように拒否されます。
追加された 著者 Keith Irwin,

CHECK制約を使って user_id1 を常に user_id2 より小さくすることができます:

CHECK (user_id1 < user_id2)

恐らく人々は自分の友人であることは許されない。そしてINSERTの前にIDが正しい順序であることを確認してください。友だちのリストを抽出するときは、両方の列をチェックする必要があります。

select user_id2 from friendship where user_id1 = X
union all
select user_id1 from friendship where user_id2 = X

ここで X は興味のある人です.2人が友人であるかどうかを確認するには、正しい順序でIDを並べて選択してください。

3
追加された
これは素晴らしい。すべてのあなたの助けをありがとう:D
追加された 著者 lollercoaster,
いい視点ね。私がチェックしなければならない何か。 @a_horse_with_no_nameの解決策で運がない
追加された 著者 lollercoaster,
大丈夫です。私はid1> id2または何かの場合、1/0操作を行うトリガーを行うことができます。しかしそれはかなりハッキリです
追加された 著者 lollercoaster,
はい、残念ながら、CHECKsとCONSTRAINTはMySQLでは動作しません。それらは解析されますが、挿入/更新呼び出しでは無視されます
追加された 著者 lollercoaster,
user_id1のように価値の低いIDを取得するにはどうすればよいですか?
追加された 著者 lollercoaster,
@ lollercoaster:もしあなたがMySQLに合格すれば、あなたはkludgesに悩まされています。 CHECK制約はなく、AFAIK MySQLトリガには例外を発生させるためのメカニズムが定義されていないため、何らかのエラーが発生していることがわかります。また、「ゼロによる除算」は「無効なID順序」を意味します。そして、静かにNULLを返すのではなく、 1/0 が例外を送出することは確実ですか?
追加された 著者 mu is too short,
@lolcocoaster:a_horse_with_no_nameと私はどちらもPostgreSQLに傾いており、はるかに優れた機能セットを持っていますが、PostgreSQLには再帰的なCTEがあり、グラフやツリーの作業に便利です。 MySQLを使用したい場合、トリガから例外を発生させる「標準的な」方法はAFAIKであり、ある種の不正な操作をトリガーします。このようなものはあまりにも醜いことなくうまくいくかもしれません: blogs.oracle.com/svetasmirnova/entry/how_to_raise_error_in
追加された 著者 mu is too short,
@lolcocoaster:あなたのコメントは、MySQLの最初の言及です。トリガで偽装したり、より良いデータベースに切り替えたり、コードにINSERTやUPDATEのバグがないと仮定して、ベストを願ったりするかもしれません。
追加された 著者 mu is too short,
@lolcocoaster:それは重複を避ける。あなたが強制的に(CHECKを使って)最初のノードのIDをより低くすることを強制するならば、(1,2)(2,1) (2,1)は違反するため、2番目のノードでは(1,2)(2,1)チェック制約。
追加された 著者 mu is too short,

インデックスが適切に設定されていれば、 user1、user2user2、user1 の両方を格納することに問題はありません。

1つの行だけが必要な場合は、user1に最低のIDを格納することをお勧めします(それを強制するためにその列に制約を設定することさえあるかもしれません)。

SELECT user1 FROM friendship WHERE user2 = $user_id
UNION ALL
SELECT user2 FROM friendship WHERE user1 = $user_id
2
追加された
私はストレージについて心配していますか?それぞれ2回保管するのは馬鹿だと思われる。
追加された 著者 lollercoaster,
UNION ALLはUNIONよりも優れた呼び出しであり、データベースの作業量が少なくて済み、重複は発生しません。
追加された 著者 mu is too short,
クエリが簡単になります。また、常にuser1に最低値を格納すると、重複を持つことはできません。ユーザー14の友達ユーザー18の場合は、14,18を保存します。しかし、ユーザー18がユーザー14を歓迎した場合、14,18も保管します。
追加された 著者 Gustav Bertram,
そうです、私はあなたの答えを私のものよりも高くしました。それと、あなたは実際のチェック制約を提供しました。
追加された 著者 Gustav Bertram,
INSERT INTO friendship (user_id1, user_id2) 
SELECT , FROM 
WHERE ((,) NOT IN
       ((SELECT user_id1, user_id2 FROM friendship)
        UNION 
        (SELECT user_id2, user_id1 FROM friendship)))

To explain this from bottom to top, we're first constructing the table of all pairs in either direction. Then we're finding out whether or not the pair (, ) is in it. If it is, no tuples are returned by the SELECT query on line 2 and so nothing is inserted. If it is not, then one tuple is returned by the SELECT query (specifically the tuple (,)) and it is inserted.

私はa_horse_with_no_nameの答えはおそらく、この特定のケースで最もよく似たケースだと思いますが、そのようなインデックスの追加が許可されていないか、問題を引き起こしている状況にあった場合(たとえば、いくつかの行だけが意味のある友情エントリを持っていたが、依然として一意性を必要とする複雑なテーブル)、このクエリはジョブを実行します。

0
追加された
私は1列の特別なテーブルが何のためであるか理解していない...?
追加された 著者 lollercoaster,
SELECT 1 FROM friendshipを実行すると、フレンドシップ・テーブルのすべての行に対して1が得られます。したがって、SELECTを使用して値を計算する場合は、1つの行のみを持つ表が必要なので、最大で1つの値のコピーを取得できます。いくつかのRBDMSにはこの目的のための特別なテーブルがありますが、使用しているRBDMSがわからないので、何を呼び出すべきかわかりません。しかし、1つの行だけを持つテーブルを作成して使用することができます。
追加された 著者 Keith Irwin,