![]() |
Datenbank: Firebird • Version: 2.5 • Zugriff über: Zeos
Unique bei 4 verschiedenen Feldern
Ohh
Mir fällt keine guter Titel ein sorry. Ich habe vier Felder
Delphi-Quellcode:
und möchte das die Datenbank die vier Felder
ZTable1ORDER1 : TLargeintField;
ZTable1ORDER2 : TLargeintField; ZTable1ORDER3 : TLargeintField; ZTable1ORDER4 : TLargeintField; auf Unique überprüft. Also ob der eingegebene Wert schon vorhanden ist. Also wenn ich ZTable1ORDER1.Value = 5 und ZTable1ORDER3.Value = 5 das die Datenbank dann meckert. Ist das verständlich, was ich möchte ?:pale: |
AW: Unique bei 4 verschiedenen Feldern
NOrmalerweise hätte ich geschrieben, nimm einen Unique Constraint. Aber der gilt über alle Felder, einzelne Werte dürfen dabei sehr wohl identisch sein, nicht aber die Kombination aller Werte.
Welche Wertebereiche gibt es denn hier, Du könntest mit expliziten Constraints arbeiten, die Feldgleichheit verbieten. Kommt mir aber etwas murxig vor. Hast Du die Möglichkeit einen Insert/Update Trigger anzulegen, der diese Prüfung vornimmt? Grundsätzlich ist das Anliegen ungewöhnlich, bist Du sicher, dass Dein Datenmodell ok ist? Um's nochkurz zu schreiben, diese denormalisierten Spalten mit den 4 Orders sind nicht schön. Das wäre besser eine Liste mit Orders, dann hättest Du kein Problem, weder jetzt noch wenn mal "Order5", 6 oder 7 hinzukommt. Dazu müsste man dann weder die DB noch das Programm groß umbauen. |
AW: Unique bei 4 verschiedenen Feldern
Da würde sich doch ein Trigger auf der Datenbank anbieten.
Einfach mal Tante Google fragen -> ![]() |
AW: Unique bei 4 verschiedenen Feldern
Geht sowas im Firebird nicht?
SQL-Code:
Oder kann dieser Constraint nur jeweils ein Feld behandeln? (konnte ich auf die Schnelle nicht aus der Doku erkennen)
CREATE TABLE irgendwas (
ZTable1Order1 INTEGER, ZTable1Order2 INTEGER, ZTable1Order3 INTEGER, ZTable1Order4 INTEGER, .. CONSTRAINT uk_ZTable1Order UNIQUE (ZTable1Order1, ZTable1Order2, ZTable1Order3, ZTable1Order4) ) Im Prostgress mußte ich es aber auch mal so lösen, weil ich auch das NULL unique haben wollte.
SQL-Code:
CONSTRAINT uk_ZTable1Order UNIQUE (COALESCE(ZTable1Order1, ''), COALESCE(ZTable1Order2, ''), COALESCE(ZTable1Order3, ''))
[edit] ich mein natürlich mit einer 0, oder einem anderem nichtgenutzen Wert anstatt dem '' |
AW: Unique bei 4 verschiedenen Feldern
Zitat:
Weiß nicht ob FB das kann. Weiß auch nicht, ob es das Problem des TE beseitigt. |
AW: Unique bei 4 verschiedenen Feldern
Hab die beiden Zeilen in der mitte mal ausgetauscht. (die Frage zuerst und dann den Text zum Code darunter auch nach da unten).
War wohl etwas verwirrend so (hatte beim Umkopieren wohl nicht richtig aufgepasst) Aso, ich glaub jetzt hab ich das verstanden. Es sind 4 Felder und ein Wert "Integer" darf nur einmal vorkommen, egal in welchem Feld. Oder meinst du daß ein Wert pro Zeile nur einmal vorkommen darf? Bei mir dufte nur eine "Gruppe" aus 4 Integer einmal vorkommen. Hmmm, dann bleibt wohl wirklich nur der Trigger. > in allen vier Feldern prüfen, ob der Wert nirgendwo vorkommt, abgesehn von dem Feld, was grade geprüft wird. |
AW: Unique bei 4 verschiedenen Feldern
Wenn ich es richtig verstanden habe geht es nicht um eine einmalige Kombination der 4 Felder, sondern um Einmaligkeit des Wertes über alle 4 Felder. Ich kann es ohne Detailkenntnisse nicht wirklich beurteilen, aber ich muss jobo zustimmen, dass das zumindest nach fehlender Normalisierung riecht. Ein paar Zusatzinfos könnten hilfreich sein.
|
AW: Unique bei 4 verschiedenen Feldern
Zitat:
Code:
Will meinen: wenn ZTable1ORDER1.Value und ZTable1ORDER3.Value identische Werte aufweisen, dann ist das ein Fehler, die Werte von ZTable1ORDER2.Value und ZTable1ORDER4.Value sind bei der Prüfung irrelevant.
ZTable1ORDER1.Value = 5
and ZTable1ORDER2.Value = beliebiger Wert and ZTable1ORDER3.Value = 5 -> Fehler and ZTable1ORDER4.Value = beliebiger Wert ZTable1ORDER1.Value = 5 and ZTable1ORDER2.Value = beliebiger Wert and ZTable1ORDER3.Value = alles außer 5 -> ok and ZTable1ORDER4.Value = beliebiger Wert Dann wäre himitsus Ansatz dahingehend abzuändern:
SQL-Code:
ist aber gemeint:
CREATE TABLE irgendwas (
ZTable1Order1 INTEGER, ZTable1Order2 INTEGER, ZTable1Order3 INTEGER, ZTable1Order4 INTEGER, .. CONSTRAINT uk_ZTable1Order UNIQUE (ZTable1Order1, ZTable1Order3) )
Code:
Will meinen: Wenn eine Zahl mehr als einmal in einer beliebigen Kombination der Spalten vorkommen könnte, wäre dies ein Fehler.
ZTable1ORDER1.Value = 5
and (ZTable1ORDER2.Value = 5 or ZTable1ORDER3.Value = 5 or ZTable1ORDER4.Value = 5) -> Fehler ZTable1ORDER1.Value = 5 and (ZTable1ORDER2.Value = alles außer 5 or ZTable1ORDER3.Value = alles außer 5 or ZTable1ORDER4.Value = alles außer 5) -> ok ZTable1ORDER1.Value = 5 and (ZTable1ORDER2.Value = alles außer 5 or ZTable1ORDER3.Value = 5 or ZTable1ORDER4.Value = 5) -> Fehler
SQL-Code:
sofern die Datenbank mehrere Constraints auf einer Tabelle zulässt.
CREATE TABLE irgendwas (
ZTable1Order1 INTEGER, ZTable1Order2 INTEGER, ZTable1Order3 INTEGER, ZTable1Order4 INTEGER, .. CONSTRAINT uk_ZTable1Order1 UNIQUE (ZTable1Order1, ZTable1Order2) CONSTRAINT uk_ZTable1Order2 UNIQUE (ZTable1Order1, ZTable1Order3) CONSTRAINT uk_ZTable1Order3 UNIQUE (ZTable1Order1, ZTable1Order4) CONSTRAINT uk_ZTable1Order4 UNIQUE (ZTable1Order2, ZTable1Order3) CONSTRAINT uk_ZTable1Order5 UNIQUE (ZTable1Order2, ZTable1Order4) CONSTRAINT uk_ZTable1Order6 UNIQUE (ZTable1Order3, ZTable1Order4) ) Ich gehe dabei davon aus, dass die Zahl 5 als Platzhalter für eine beliebige Zahl steht und nicht explizit als abzufragender Wert gemeint ist. Zitat:
|
AW: Unique bei 4 verschiedenen Feldern
SQL-Code:
CONSTRAINT uk_ZTable1Order1 UNIQUE (ZTable1Order1, ZTable1Order2)
entspricht quasi einem
SQL-Code:
CONSTRAINT uk_ZTable1Order1 UNIQUE (ZTable1Order1 || ',' || ZTable1Order2)
Was du brauchst ist eher ein CheckConstraint mit
SQL-Code:
(NULLs müsste man noch beachten/behandeln)
(Field1 <> Field2) AND (Field1 <> Field3) AND (Field1 <> Field4) AND (Field2 <> Field3) AND (Field2 <> Field4) AND (Field3 <> Field4)
bzw.
SQL-Code:
(Field1 NOT IN [Field2, Field3, Field4]) AND (Field2 NOT IN [Field3, Field4]) AND (Field3 <> Field4)
|
AW: Unique bei 4 verschiedenen Feldern
Zitat:
|
AW: Unique bei 4 verschiedenen Feldern
Danke Danke,
werde ich morgen mal versuchen umzusetzen :thumb: |
AW: Unique bei 4 verschiedenen Feldern
Ich möchte mich noch mal bei allen bedanken,:-D
ich dachte schon das bekommst Du leider nicht hin und dann habe ich es mal mit "=" probiert und es klappte wunderbar. bei "<>" oder "not in" hat SQL Firebird, dass nur in der gleichen Zeile richtig angemeckert, warum ? Keine Ahnung !
SQL-Code:
/* Check constraints definition */ ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK2_FOLDERDSG CHECK (ORDER1 = ORDER3); ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK3_FOLDERDSG CHECK (ORDER1 = ORDER4); ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK4_FOLDERDSG CHECK (ORDER2 = ORDER3); ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK5_FOLDERDSG CHECK (ORDER2 = ORDER4); ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK6_FOLDERDSG CHECK (ORDER3 = ORDER4); ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK1_FOLDERDSG CHECK (ORDER1 = ORDER2); /******************************************************************************/ /* Unique Constraints */ /******************************************************************************/ ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ1_FOLDERDSG UNIQUE (ORDER1) USING INDEX "_IDXORDER1"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ2_FOLDERDSG UNIQUE (ORDER2) USING INDEX "_IDXORDER2"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ3_FOLDERDSG UNIQUE (ORDER3) USING INDEX "_IDXORDER3"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ4_FOLDERDSG UNIQUE (ORDER4) USING INDEX "_IDXORDER4"; |
AW: Unique bei 4 verschiedenen Feldern
Sicher daß es nicht
Delphi-Quellcode:
anstatt
!=
Delphi-Quellcode:
heißt?
<>
Vieleicht geht auch nur
Delphi-Quellcode:
NOT (X IN [...])
Kenn mich mit der Syntax vom FB nicht so aus, aber da gibt es ja die komischsten Dinge. Und wenn die Felder auch noch die NULL enthalten können, dann muß man eventuell aufpassen, wie die Vergleichsoperatoren darauf reagieren. Zitat:
SQL-Code:
Gut, bei deiner Variante bekommt man wenigstens noch an Hand des Constraint-Namens mit, welche Felder da in Konflikt stehen.
ALTER TABLE "FolderDsg" ADD CONSTRAINT CHK_FOLDERDSG CHECK ((ORDER1 = ORDER2) AND (ORDER1 = ORDER3)
AND (ORDER1 = ORDER4) AND (ORDER2 = ORDER3) AND (ORDER2 = ORDER4) AND (ORDER3 = ORDER4)); |
AW: Unique bei 4 verschiedenen Feldern
:oops:Ganz so einfach ist es wohl doch nicht !
Ich habe die Datenbank neu aufgesetzt und nun geht das leider nicht mehr wie erhofft. Da muss ein Trigger im Spiel gewesen sein den ich mit Zufall ausgelöst hatte. Werde berichten wenn ich das gelöst habe |
AW: Unique bei 4 verschiedenen Feldern
Hallo
Danke noch mal für die Hilfen, Nachdem ich mich ein wenig mit SQL beschäftigt habe, möchte ich meine Lösung präsentieren. Ich habe einfach eine neue Tabelle Dummy erstellt und schreibe da einfach alle Werte in DUMMYCOUNTER hinein. Das Feld ist auch Unique und meckert wenn was 2 mal versucht wird einzugeben. Falls mal ein Datensatz gelöscht werden soll, wird dieser auch in DUMMYCOUNTER gelöscht. Vielleicht weiss ja jemand eine Verinfachung des ganzen ?
SQL-Code:
******************************************************************************/
/* Unique Constraints */ /******************************************************************************/ ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ1_FOLDERDSG UNIQUE (ORDER1) USING INDEX "_IDXORDER1"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ2_FOLDERDSG UNIQUE (ORDER2) USING INDEX "_IDXORDER2"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ3_FOLDERDSG UNIQUE (ORDER3) USING INDEX "_IDXORDER3"; ALTER TABLE "FolderDsg" ADD CONSTRAINT UNQ4_FOLDERDSG UNIQUE (ORDER4) USING INDEX "_IDXORDER4"; CREATE UNIQUE INDEX "FolderDsg_IDX1" ON "FolderDsg" (ORDER1, ORDER2, ORDER3, ORDER4); /******************************************************************************/ /* Triggers */ /******************************************************************************/ /* Trigger: FOLDERDSG_DELETE */ CREATE OR ALTER TRIGGER FOLDERDSG_DELETE FOR "FolderDsg" ACTIVE BEFORE DELETE POSITION 1 AS declare variable theorder1 bigint; begin if (OLD.order1 is not null) then begin theorder1 = OLD.order1; DELETE FROM DUMMY WHERE DUMMYCOUNTER = :theorder1; end if (OLD.order2 is not null) then begin theorder1 = OLD.order2; DELETE FROM DUMMY WHERE DUMMYCOUNTER = :theorder1; end if (OLD.order3 is not null) then begin theorder1 = OLD.order3; DELETE FROM DUMMY WHERE DUMMYCOUNTER = :theorder1; end if (OLD.order4 is not null) then begin theorder1 = OLD.order4; DELETE FROM DUMMY WHERE DUMMYCOUNTER = :theorder1; end end ^ /* Trigger: FOLDERDSG_UPDATE */ CREATE OR ALTER TRIGGER FOLDERDSG_UPDATE FOR "FolderDsg" ACTIVE AFTER UPDATE POSITION 0 AS declare variable theorder1 bigint; declare variable theorder2 bigint; begin if (OLD.order1 is not null) then begin theorder1 = NEW.order1; theorder2 = OLD.order1; update DUMMY set DUMMYCOUNTER = :theorder1 WHERE DUMMYCOUNTER = :theorder2; end -- that works well ---- if ((OLD.order1 is null) and NEW.order1 is not null ) then begin INSERT INTO DUMMY (DUMMYCOUNTER) values (NEW.order1); end ----------------------------------------- if (OLD.order2 is not null) then begin theorder1 = NEW.order2; theorder2 = OLD.order2; update DUMMY set DUMMYCOUNTER = :theorder1 WHERE DUMMYCOUNTER = :theorder2; end -- that works well ---- if ((OLD.order2 is null) and NEW.order2 is not null ) then begin INSERT INTO DUMMY (DUMMYCOUNTER) values (NEW.order2); end ----------------------------------------- if (OLD.order3 is not null) then begin theorder1 = NEW.order3; theorder2 = OLD.order3; update DUMMY set DUMMYCOUNTER = :theorder1 WHERE DUMMYCOUNTER = :theorder2; end -- that works well ---- if ((OLD.order3 is null) and NEW.order3 is not null ) then begin INSERT INTO DUMMY (DUMMYCOUNTER) values (NEW.order3); end ----------------------------------------- if (OLD.order4 is not null) then begin theorder1 = NEW.order4; theorder2 = OLD.order4; update DUMMY set DUMMYCOUNTER = :theorder1 WHERE DUMMYCOUNTER = :theorder2; end -- that works well ---- if ((OLD.order4 is null) and NEW.order4 is not null ) then begin INSERT INTO DUMMY (DUMMYCOUNTER) values (NEW.order4); end ----------------------------------------- end ^ |
AW: Unique bei 4 verschiedenen Feldern
Sehe ich das richtig, dass alle 4 Spalten einzeln und in Kombination eindeutig sein sollen? Und dann noch zusätzlich über alle 4 Spalten?
|
AW: Unique bei 4 verschiedenen Feldern
Zitat:
zum Code: Ist es unter Firebird notwendig die Werte erst in Variablen zu schreiben? Sonst kann man direkt new/old Werte in die Statements setzen. Das Update find ich etwas übertrieben. Entweder es gibt einen Wert, dann Insert oder es wird einer entfernt, dann delete. Nun nochmal meine Eingangsbemerkung: Das Konstrukt ist ziemlich daneben. Der Clou aber ist nun: Die von Dir entworfene Hilfskonstruktion ist ziemlich nahe an dem, wie es normalerweise umgesetzt würde (mit dem Vorteil, das man ohne Modelländerung beliebig viele Werte verwalten kann statt maximal 4) Diese denormalisierten Felder laufen natürlich auch an jeder anderen Stelle, wo sie verwendet werden, gegen die relationalen Prinzipien und verursachen Extra (Code) Aufwand. Falls Du das grad erfunden hast, wirf es wieder weg. Falls es sich um ein bestehendes System handelt, versuch lieber, es abzuschaffen. Das eigenartige bei solchen Lösungen ist ja meist, dass irgendwer meint, auf diese Weise etwas Aufwand zu sparen. "Nein, dafür machen wir nicht extra ne neue Tabelle!" |
AW: Unique bei 4 verschiedenen Feldern
jobo ich bin Hobby Programmierer. Das funktioniert gut ist es.
Wenn Du eine bessere Lösung weißt nur zu. Ich habe ein CASE bei ![]() aufgemacht und da hat mir jemand dazu geraten. Das Problem ist das Firebird nur die Uniques in der gleichen Spalte oder Zeile anmeckert. Ich habe etwas mehr über Datenbanken gelern und das freut mich sehr. Danke für eure Hilfen. |
AW: Unique bei 4 verschiedenen Feldern
Zitat:
Viele der Kommentare bei SO sind aber die selben wie der von Jobo und anderen hier: Du hast zwar eine Lösung für dein Problem gefunden, aber du hättest erst gar nicht das Problem, wenn du deine Tabellenstruktur evtl. anders designed hättest. Darauf wollten die vielen dezenten Hinweise glaub ich hinaus. Da aber nie gesagt wurde, wofür das eigentlich gedacht ist, konnte man nicht konkreter sagen, was man hätte anders/besser machen können, daher immer nur Sätze ala: "Überdenk mal deine Datenstruktur", die nicht böse gemeint waren (so wie ich die lese) sondern als guter Rat gedacht. Beispiel zu einer Lösung, die deiner ähnelt, einer Normalisierung aber näher kommt könnte sein, deine Dummy-Tabelle so zu gestellten, dass sie drei Spalten hat. Spalte 1 eine ID mit der du sie mit der Haupttabelle verknüpfst. Spalte 2 für die Werte 1-4 die deinen vier Feldern aus der Haupttabelle entsprechen und Spalte drei in der diese "einmaligen" Zahlen kommen sollen. Schlüssel ist dann Spalte 1. Unique muss die Kombination aus 1 und 2 sein, und Unique muss der Wert in Spalte 3 sein. Sieht vllt. zunächst nach mehr Arbeit aus, als deine Version, aber man muss weniger programmieren, kann mehr der DB überlassen, und kann's leicht erweitern auf 5 oder 6 Felder in denen die Zahlen eindeutig sein müssen. Und man sieht in der Dummy-Tabelle, wozu dortige Einträge gehören. |
AW: Unique bei 4 verschiedenen Feldern
Wahrscheinlich habe ich da etwas falsch verstanden, aber wenn die (Schlüssel) in allen 4 Spalten unique sin sollen, warum werden sie nicht von einem Generator erzeugt und gut ist?
Gruß K-H |
AW: Unique bei 4 verschiedenen Feldern
Es könnte sich aber auch (versteckt) um eine 1:n-Relation handeln. Dann müsste man "nur" die 4 Spalten aus der Haupttabelle löschen und eine weitere Tabelle mit mindestens 3 Spalten anlegen: ID, Fremdschlüsselfeld auf Haupttabelle und Wert. Die letzteren beiden erhalten in Kombination einen eindeutigen Index, und man sollte das erhalten, was anfangs gewünscht war: je Hauptsatz darf jeder Wert nur einmal vorkommen.
|
AW: Unique bei 4 verschiedenen Feldern
@ATS3788
Ich versteh ehrlich gesagt nicht, warum Du die Gelegenheit nicht nutzt und allen Rätselratenden hier erklärst, wofür die Konstruktion eigentlich gedacht ist. Dein (akutes) Problem hast Du ja sogar behoben! Was Du erreichen willst, erklären eigentlich nur Deine- zuletzt selbst gelieferten- Constraints und Trigger auf Basis eines vermutlich unpraktischen Lösungsansatzes. Es hindert Dich doch niemand zu schreiben, was Du mit diesen 4 Spalten erreichen willst. Meine und auch die Einwände der anderen sind sicher nicht als Vorwurf zu verstehen, so wie Jumpy es auch bereits geschrieben hat. Und noch mal zu der "verrückten" Sache an dem Problem: Dein Hilfskonstrukt mit der Dummy Table ist eigentlich für sich allein genommen schon der richtige Weg es umzusetzen! (sofern ich das problem richtig verstanden habe) |
AW: Unique bei 4 verschiedenen Feldern
Wahrscheinlich habe ich da etwas falsch verstanden, aber wenn die (Schlüssel) in allen 4 Spalten unique sin sollen, warum werden sie nicht von einem Generator erzeugt und gut ist?
Weil es dynamisch sein soll und weil mir das erst sehr viel später eingefallen ist und weil es eine Herausforderung für mich war und weil es hier so viel fähige nette Leute gibt, die ich gerne mal auf ein Bier einladen würde.:thumb: |
AW: Unique bei 4 verschiedenen Feldern
Ein Bier?!
Ich bin im Frühjahr in Frankfurt irgendwo, dann komm ich mal vorbei! ;) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz