2012-11-06 13 views
7

Wir haben eine Tabelle mit einer eindeutigen Einschränkung für Feedback von einem Benutzer, für einen anderen, in Bezug auf einen Verkauf.Eindeutige Einschränkung mit weichen gelöschten Zeilen ausgeschlossen

ALTER TABLE feedback 
ADD CONSTRAINT unique_user_subject_and_sale 
UNIQUE (user_id, subject_id, sale_id) 

Dies stellt sicher, dass wir nicht versehentlich doppelte Zeilen von Feedback erhalten.

Zur Zeit löschen wir manchmal hart Feedback löschen links und lassen Sie den Benutzer verlassen es erneut. Wir wollen Soft löschen ändern:

ALTER TABLE feedback 
ADD COLUMN deleted_at timestamptz 

Wenn deleted_at IS NOT NULL, betrachten das Feedback gelöscht, wenn wir noch den Audit-Trail in unserer DB (und wahrscheinlich teilen Sie Ihre Website-Administratoren geister out).

Wie können wir unsere einzigartige Einschränkung beibehalten, wenn wir so ein Soft-Delete verwenden? Ist es möglich, ohne eine allgemeinere CHECK() Einschränkung zu verwenden, die eine Aggregatprüfung durchführt (ich habe nie versucht, Prüfbeschränkung wie dieses zu verwenden).

Es ist wie ich eine WHERE-Klausel an die Einschränkung anfügen müssen.

Antwort

14

Ihre eindeutigen Index tun, später bearbeitet out .

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 

Ihr eindeutiger Index hat mindestens zwei Nebeneffekte, die Ihnen möglicherweise Probleme bereiten.

  1. In anderen Tabellen können Sie keine Fremdschlüsseleinschränkung festlegen, die auf "Feedback" verweist. Eine Fremdschlüsselreferenz erfordert eine Kombination von Spalten, die entweder als primary key oder unique deklariert werden.
  2. Ihr eindeutiger Index erlaubt mehrere Zeilen, die sich im Zeitstempel "deleted_at" von nur unterscheiden. So ist es möglich am Ende mit Zeilen, die wie das folgende Beispiel aussehen. Ob dies ein Problem ist, hängt von der Anwendung ab.

Beispiel

user_id subject_id sale_id deleted_at 
-- 
1  1   1  2012-01-01 08:00:01.33 
1  1   1  2012-01-01 08:00:01.34 
1  1   1  2012-01-01 08:00:01.35 

PostgreSQL Dokumente dieser Art von Index als Teilindex, sollten Sie müssen irgendwann an Google. Andere Plattformen verwenden andere Begriffe für sie - gefilterter Index ist eins. Mit einem Paar Teilindizes können Sie die Probleme bis zu einem gewissen Grad begrenzen.

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale_not_null 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NOT NULL 

Aber Ich sehe keinen Grund, auf diese viel Mühe zu gehen, vor allem mit Fremdschlüsseln die möglichen Probleme gegeben. Wenn Ihre Tabelle

create table feedback (
    feedback_id integer primary key, 
    user_id ... 
    subject_id ... 
    sale_id ... 
    deleted_at ... 
    constraint unique_user_subj_sale 
    unique (user_id, subject_id, sale_id) 
); 

wie diese sieht dann alles, was Sie brauchen, ist, dass eindeutige Einschränkung auf {user_id, subject_id, sale_id}. Sie können darüber hinaus in Erwägung ziehen, alle Löschungen die Spalte "deleted_at" zu verwenden, anstatt einen Löschvorgang durchzuführen.

+0

Ich habe das vollständige Schema nicht veröffentlicht, aber Feedback hat einen ganzzahligen (seriellen) Primärschlüssel. Darüber hinaus werden user_id, sale_id und subject_id als Fremdschlüssel deklariert (und haben Indizes). Wir müssen nur die Eindeutigkeit als zusätzliche Einschränkung durchsetzen. – d11wtq

+0

Und ja, es ist in Ordnung für den eindeutigen Index, Zeilen zu erlauben, die sich nur im deleted_at-Zeitstempel unterscheiden ... das ist die Sache, die ich erreichen wollte;) – d11wtq

+1

Wenn Sie a) einen seriellen Primärschlüssel und b) einen partiellen haben Index wie beschrieben und wie ich getestet habe, haben Sie immer noch ein potentielles Problem mit anderen Tabellen, die auf "Feedback" verweisen. Angenommen, die drei Zeilen, die ich im obigen Beispiel gepostet habe, haben die seriellen Primärschlüssel 1, 2 und 3. Welchen von diesen wählt eine referenzierende Tabelle für ihren Fremdschlüssel? Wie können alle referenzierenden Tabellen den * gleichen * Wert auswählen? –

6

Trotz der Tatsache, die Dokumentation PostgreSQL abrät einen eindeutigen Index anstelle einer Einschränkung verwendet (wenn der Punkt eine Einschränkung zu haben ist), scheint es Sie

CREATE UNIQUE INDEX feedback_unique_user_subject_and_sale 
ON feedback(user_id, subject_id, sale_id) 
WHERE deleted_at IS NULL 
+0

Wird als "Teilindex" bezeichnet. Unter @ Catcalls Post finden Sie wichtige Einschränkungen. –

Verwandte Themen