Zum Beispiel mit einer Tabelle ähnlich der folgenden:
create table foo(bar int identity, chk char(1) check (chk in('Y', 'N')));
Es ist egal, ob das Flag als char(1)
, a bit
oder was auch immer implementiert ist . Ich möchte nur in der Lage sein, die Einschränkung durchzusetzen, dass sie nur für eine einzelne Zeile festgelegt werden kann.
constraint
database-agnostic
referential-integrity
Jack Douglas
quelle
quelle
Antworten:
SQL Server 2008 - Gefilterter eindeutiger Index
quelle
SQL Server 2000, 2005:
Sie können die Tatsache nutzen, dass in einem eindeutigen Index nur eine Null zulässig ist:
für 2000 benötigen Sie möglicherweise
SET ARITHABORT ON
(danke an @gbn für diese Info)quelle
Orakel:
Da Oracle keine Einträge indiziert, bei denen alle indizierten Spalten null sind, können Sie einen funktionsbasierten eindeutigen Index verwenden:
Dieser Index indiziert immer höchstens eine einzelne Zeile.
In Kenntnis dieses Indexfaktors können Sie die Bitspalte auch etwas anders implementieren:
Hier werden die möglichen Werte für die Spalte
chk
wirdY
undNULL
. Maximal eine Zeile kann den Wert habenY.
quelle
not null
Einschränkung?not null
Einschränkung hinzufügen , wenn Sie keine Nullen möchten (das war mir aus den Fragenspezifikationen nicht klar). In jedem Fall kann nur eine Zeile den Wert 'Y' haben.default
)?Y
oder seinnull
kann. Sehen Sie sich mein Update an.null
s übersprungen werden - auf Kosten der Klarheit vielleichtIch denke, dies ist ein Fall der richtigen Strukturierung Ihrer Datenbanktabellen. Um es konkreter zu machen: Wenn Sie eine Person mit mehreren Adressen haben und eine als Standardadresse festlegen möchten, sollten Sie die Adress-ID der Standardadresse in der Personentabelle und keine Standardspalte in der Adresstabelle speichern:
Sie können die DefaultAddressID auf null setzen, aber auf diese Weise erzwingt die Struktur Ihre Einschränkung.
quelle
MySQL:
Check - Bedingungen werden in MySQL ignoriert , so dass wir betrachten haben
null
oderfalse
als falsch undtrue
als wahr. Höchstens 1 Reihe kann habenchk=true
Sie können es eine Verbesserung betrachten einen Trigger zu ändern hinzuzufügen
false
intrue
auf insert / update als Abhilfe für das Fehlen einer Check - Einschränkung - IMO es aber nicht eine Verbesserung.Ich hatte gehofft, ein char (0) verwenden zu können, weil es
Leider bekomme ich zumindest mit MyISAM und InnoDB
--bearbeiten
Dies ist schließlich keine gute Lösung, da MySQL
boolean
ein Synonym fürtinyint(1)
ist und daher Werte ungleich Null als 0 oder 1 zulässt. Möglicherweise ist diesbit
eine bessere Wahlquelle
null
,false
,true
- ich Wunder tun , wenn es etwas sauberer ist ...SQL Server:
Wie es geht:
Der beste Weg ist ein gefilterter Index. Verwendet DRI
SQL Server 2008+
Berechnete Spalte mit Eindeutigkeit. Verwendet DRI
Siehe die Antwort von Jack Douglas. SQL Server 2005 und früher
Eine indizierte / materialisierte Ansicht, die einem gefilterten Index ähnelt. Verwendet DRI
Alle Versionen.
Auslösen. Verwendet Code, nicht DRI.
Alle Versionen
Wie man es nicht macht:
Siehe Eins Zwei Drei Vier
quelle
PostgreSQL:
--bearbeiten
oder (viel besser) einen eindeutigen Teilindex verwenden :
quelle
Diese Art von Problem ist ein weiterer Grund, warum ich diese Frage gestellt habe:
Anwendungseinstellungen in der Datenbank
Wenn Sie eine Anwendungseinstellungstabelle in Ihrer Datenbank haben, könnten Sie einen Eintrag haben, der auf die ID des einen Datensatzes verweist, den Sie als "speziell" betrachten möchten. Dann sehen Sie einfach in Ihrer Einstelltabelle nach, um welche ID es sich handelt. Auf diese Weise benötigen Sie keine ganze Spalte für nur einen einzustellenden Eintrag.
quelle
Mögliche Ansätze unter Verwendung weit verbreiteter Technologien:
1) Entziehen Sie der Tabelle die Schreibrechte. Erstellen Sie CRUD-Prozeduren, die sicherstellen, dass die Einschränkung an den Transaktionsgrenzen erzwungen wird.
2) 6NF: Lassen Sie die
CHAR(1)
Säule fallen. Fügen Sie eine Referenzierungstabelle hinzu, die eingeschränkt ist, um sicherzustellen, dass ihre Kardinalität eine nicht überschreitet:Ändern Sie die Anwendungssemantik so, dass als "Standard" die Zeile in der neuen Tabelle gilt. Verwenden Sie möglicherweise Ansichten, um diese Logik zu kapseln.
3) Lassen Sie die
CHAR(1)
Säule fallen. Fügen Sie eineseq
Ganzzahlspalte hinzu. Legen Sie eine eindeutige Einschränkung aufseq
. Ändern Sie die Anwendungssemantik so, dass als "Standard" die Zeile gilt, in der derseq
Wert eins oder derseq
Wert der größte / kleinste Wert oder ähnliches ist. Verwenden Sie möglicherweise Ansichten, um diese Logik zu kapseln.quelle
Für diejenigen, die MySQL verwenden, ist hier eine geeignete gespeicherte Prozedur:
Gehen Sie folgendermaßen vor, um sicherzustellen, dass Ihre Tabelle sauber ist und die gespeicherte Prozedur funktioniert, vorausgesetzt, ID 200 ist die Standardeinstellung:
Hier ist ein Trigger, der ebenfalls hilft:
Führen Sie die folgenden Schritte aus, um sicherzustellen, dass Ihre Tabelle sauber ist und der Trigger funktioniert, vorausgesetzt, ID 200 ist der Standardwert:
Versuche es !!!
quelle
In SQL Server 2000 und höher können Sie indizierte Ansichten verwenden, um komplexe Einschränkungen (oder Einschränkungen für mehrere Tabellen) wie die von Ihnen angeforderten zu implementieren.
Auch Oracle hat eine ähnliche Implementierung für materialisierte Ansichten mit verzögerten Prüfbedingungen.
Siehe meinen Beitrag hier .
quelle
Standard Transitional SQL-92, weit verbreitet, z. B. SQL Server 2000 und höher:
Entziehen Sie der Tabelle die Schreibrechte. Erstellen Sie zwei Ansichten für
WHERE chk = 'Y'
undWHERE chk = 'N'
jeweils einschließlichWITH CHECK OPTION
. Für dieWHERE chk = 'Y'
Ansicht eine Suchbedingung ein, deren Kardinalität eine solche nicht überschreiten darf. Gewähren Sie Schreibberechtigungen für die Ansichten.Beispielcode für die Views:
quelle
Hier ist eine Lösung für MySQL und MariaDB mit virtuellen Spalten, die etwas eleganter ist. Es erfordert MySQL> = 5.7.6 oder MariaDB> = 5.2:
Erstellen Sie eine virtuelle Spalte mit dem Wert NULL, wenn Sie die Unique-Einschränkung nicht erzwingen möchten:
(Verwenden Sie für MySQL
STORED
anstelle vonPERSISTENT
.)quelle
VOLLSTÄNDIGES SQL-92-Standard: Verwenden Sie eine Unterabfrage in einer
CHECK
Einschränkung, die nicht allgemein implementiert ist, z. B. in Access2000 (ACE2007, Jet 4.0, was auch immer) und höher, wenn Sie sich im ANSI-92-Abfragemodus befinden .Beispielcode: Beachten Sie, dass
CHECK
Einschränkungen in Access immer auf Tabellenebene gelten. Da dieCREATE TABLE
Anweisung in der Frage eineCHECK
Einschränkung auf Zeilenebene verwendet, muss sie leicht durch Hinzufügen eines Kommas geändert werden:quelle
Ich habe nur die Antworten durchgesehen, sodass ich möglicherweise eine ähnliche Antwort verpasst habe. Die Idee ist, eine generierte Spalte zu verwenden, die entweder pk oder eine Konstante ist, die nicht als Wert für pk existiert
AFAIK dies ist in SQL2003 gültig (da Sie nach einer agnostischen Lösung suchen). DB2 lässt dies zu, nicht sicher, wie viele andere Anbieter dies akzeptieren.
quelle