Pertanyaan Adakah cara yang elegan untuk menyimpan hubungan ganda (mis. Pengguna 1 dan pengguna 2 adalah teman)


Saya mengalami masalah yang sama dalam dua bagian kerja yang berbeda bulan ini:

Version 1: User 1 & User 2 are friends
Version 2: Axis 1 & Axis 2 when graphed should have the quadrants colored...

Masalahnya adalah, saya tidak melihat cara yang elegan, menggunakan RDBMS, untuk menyimpan dan menanyakan informasi ini.

Ada dua pendekatan yang jelas:

Pendekatan 1:

store the information twice (i.e. two db rows rows per relationship):
u1, u2, true 
u2, u1, true
u..n, u..i, true
u..i, u..n, true

have rules to always look for the inverse on updates: 
on read, no management needed
on create, create inverse
on delete, delete inverse
on update, update inverse

Advantage:    management logic is always the same.
Disadvantage: possibility of race conditions, extra storage (which is admittedly cheap, but feels wrong)

Pendekatan 2:

store the information once (i.e. one db row per relationship)
u1, u2, true
u..n, u..i, true

have rules to check for corollaries:
on read, if u1, u2 fails, check for u2, u1 
on create u1, u2: check for u2, u1, if it doesn't exist, create u1, u2
on delete, no management needed
on update, optionally redo same check as create

Advantage: Only store once
Disadvantage: Management requires different set of cleanup depending on the operation

Saya bertanya-tanya apakah ada pendekatan ke-3 yang berjalan di sepanjang garis "kunci menggunakan f (x, y) di mana f (x, y) unik untuk setiap kombinasi x, y dan di mana f (x, y) === f (y, x) "

Usus saya memberitahu saya bahwa harus ada beberapa kombinasi operasi bitwise yang dapat memenuhi persyaratan ini. Sesuatu seperti dua kolom:

key1 = x && y key2 = x + y

Saya berharap bahwa orang-orang yang menghabiskan lebih banyak waktu di departemen matematika, dan lebih sedikit waktu di departemen sosiologi telah melihat bukti kemungkinan atau ketidakmungkinan ini dan dapat memberikan cepat "[Kamu tolol,] yang mudah terbukti (im) mungkin, lihat tautan ini "(nama panggilan opsional)

Pendekatan elegan lainnya juga akan sangat disambut baik.

Terima kasih


5
2018-01-10 19:06


asal


Jawaban:


Ada juga cara menggunakan pendekatan kedua dengan menambahkan kendala tambahan. Periksa itu u1 < u2:

CREATE TABLE User
( Name VARCHAR(10) NOT NULL
, PRIMARY KEY (Name)
) ;

CREATE TABLE MutualFriendship
( u1 VARCHAR(10) NOT NULL
, u2 VARCHAR(10) NOT NULL
, PRIMARY KEY (u1, u2)
, FOREIGN KEY (u1) 
    REFERENCES User(Name)
, FOREIGN KEY (u2) 
    REFERENCES User(Name)
, CHECK (u1 < u2) 
) ;

Aturan untuk membaca, membuat, menyisipkan atau memperbarui harus menggunakan (LEAST(u1,u2), GREATEST(u1,u2)).


7
2018-01-10 20:31



Dalam SQL, mudah untuk menerapkan batasan untuk mendukung pendekatan pertama Anda:

CREATE TABLE MutualFriendship
(u1 VARCHAR(10) NOT NULL,
 u2 VARCHAR(10) NOT NULL,
 PRIMARY KEY (u1,u2),
 FOREIGN KEY (u2,u1) REFERENCES MutualFriendship (u1,u2));

INSERT INTO MutualFriendship VALUES
('Alice','Bob'),
('Bob','Alice');

2
2018-01-10 20:09



Bagi siapa pun yang tertarik, saya bermain-main dengan beberapa operasi bitwise dan menemukan bahwa yang berikut tampaknya memenuhi kriteria untuk f (x, y):

#Python, returns 3 tuple
def get_hash(x, y):
  return (x & y, x | y, x * y)

Saya tidak bisa membuktikannya.


1
2018-01-10 21:17



"x adalah teman y".

Tentukan tabel (x, y) pasangan dan terapkan bentuk kanonik, mis. x <y Ini akan memastikan bahwa Anda tidak dapat memiliki keduanya (p, q) dan (q, p) dalam database Anda, sehingga akan memastikan "simpan sekali".

Buat tampilan sebagai SELECT x, y FROM FRIENDS UNION SELECT x sebagai y, y sebagai x FROM FRIENDS.

Apakah pembaruan Anda terhadap tabel dasar (downside: pembaru harus menyadari bentuk kanonik yang diberlakukan), lakukan pertanyaan Anda terhadap tampilan.


0
2018-01-10 23:57



Anda tampaknya membatasi jumlah teman ke 1. Jika ini kasusnya maka saya akan menggunakan sesuatu seperti u1, u2 u2, u1 u3, null u4, u5 u5, u4

u3 tidak punya teman.


-2
2018-01-10 19:20