2013-03-31 16 views
5

Birincil anahtar _id olan Kullanıcılar için bir MySQL tablom var ve arkadaşlıkları (diğer kullanıcıların arkadaş listelerinde görünebilirliğini) temsil etmek istiyorum. userId yabancı anahtar çiftleri içeren tablo. Bu hem (userIdA = 2, userIdB = 7) ve (userIdA = 7, userIdB = 2) ayrı satır olarak eklenecek sağlayacak benim anlayışSipariş vermeden SQL birleşik birincil anahtar (her iki sırada da tamsayı çifti benzersiz olmalıdır)

CREATE TABLE UserFriendships (
    userIdA INT NOT NULL, 
    userIdB INT NOT NULL, 
    PRIMARY KEY (userIdA, userIdB), 
    FOREIGN KEY (userIdA) REFERENCES Users(_id) 
    FOREIGN KEY (userIdB) REFERENCES Users(_id) 
) 

: Ben böyle bir şey düşünüyorum. Arkadaşlık başına bir satır istiyorum, yani bir çift userIds için bir satır.

Bunu nasıl geliştirebileceğimi bilen var mı? Yukarıdaki kısıtlama yerine getirilmiş olsa bile, kullanıcının tüm arkadaşlarının bir listesini almak için bir birlik yapmak zorundayım, bir şey gibi: SELECT userIdB AS friendUserId WHERE userIdA = foo UNION SELECT userIdA WHERE userIdB = foo. Bu sorguyu gerçekleştirmenin en iyi yolu mu, yoksa şemamı değiştirmeyi düşünmeli miyim? (

  • userIdA

    alt kimliği ile her zaman kullanıcı ve daha yüksek kimliği

Bu şekilde her iki kombinasyon ile userIdB daima kullanıcı:

+0

Karşılıklılıkla nasıl başa çıkıyorsunuz? – Strawberry

+4

Başka bir DBMS ile oldukça kolay olurdu, ancak MySQL ile bunu önlemek için yalnızca bir tetikleyici çözüm bulabilirim. –

+0

@Strawberry Bunu düşünmemiştim, ancak bir kez karşılık verdikten sonra Kullanıcı İşbirlikleri'ne eklenmiş olan bir FriendRequests tablosu ekleyebilirim. Aynı verileri içerecek olsalar da, bu gereksiz gibi görünmüyor ... –

cevap

4

Bir iş kuralını enfore için TRIGGER BEFORE INSERT kullanabilirsiniz A, B) ve (B, A) aynı birincil anahtarla aynı sütun sırasına neden olur.

DELIMITER | 
CREATE TRIGGER enforce_friendship_id_order BEFORE INSERT ON UserFriendships 
    FOR EACH ROW BEGIN 
    SET @lowerId := IF(NEW.userIdA < NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET @higherId := IF(NEW.userIdA > NEW.userIdB, NEW.userIdA, NEW.userIdB); 
    SET NEW.userIdA = @lowerId; 
    SET NEW.userIdB = @higherId; 
    END; 
| 
DELIMITER ; 
+0

Yikes. Çalışan bir çözüm için başvurunuz, ancak bence kuralın tetiklemeden ziyade kuralsızlığı ve risk çiftlerini bırakmayı tercih ederim. Sanırım bu onlar için bir şey, ama sadece temiz hissetmiyor, biliyor musun? –

+1

iyi, evet bu, tetikleyicilerin kullanıldığı kullanım durumlarından biridir. Tablo şemasındaki bir değişikliğin size nasıl yardımcı olabileceğini anlamıyorum, bu yüzden bu cevabı yayınladım. Uygulama kodunuzda aynı işletme kuralını uygulayabilirsiniz, ancak veritabanına ait olduğunu düşünüyorum. MySQL burada gerçek bir yardım değildir. – Kaii

+0

@MikeTurley, tetikleyicilerle çok kötü bir şekilde uğraşıyor, gerçekten mi? – Kaii

İlgili konular