Check Contraint Verstoß mit Array

Fragen und Probleme rund um die Abfragespache SQL.
Antworten
thorstein
Neuer Benutzer
Beiträge: 3
Registriert: So 9. Feb 2020, 15:02

Check Contraint Verstoß mit Array

Beitrag von thorstein »

Hi,
ich hab ein Problem mit einem Check in einer variable character()[]-Spalte, siehe unten. Ohne Constraint lässt sich das INSERT ausführen - mit Constraint nicht. Das Constraint lässt sich auch ohne zu murren eingeben. Ich hab das leider noch nie gemacht und mich an ein Beispiel gehalten. Woran kanns liegen?

Code: Alles auswählen

CREATE TABLE lebmitt (
...
  typ character varying(20)[],
...
)

alter table lebmitt
add CONSTRAINT check_typ CHECK (typ::text = ANY (ARRAY[
  ...
  'natürlich'::character varying,
  'milchsauer vergoren'::character varying,
  ...
  ]::text[]));

INSERT INTO lebmitt
  (..., typ, ...)
  VALUES (
    ...,
    '{"natürlich", "milchsauer vergoren"}',
    ...);
ERROR: FEHLER: neue Zeile für Relation »lebmitt« verletzt Check-Constraint »check_typ«
DETAIL: Fehlgeschlagene Zeile enthält (..., {natürlich,"milchsauer vergoren"}, ...).

Danke!

akretschmer
Erfahrener Benutzer
Beiträge: 7715
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Re: Check Contraint Verstoß mit Array

Beitrag von akretschmer »

was genau ist jetzt das Problem? Das arbeitet wie vorgegeben. Der Check Constraint ist da, um bestimmte Eingaben nichtanzunehmen.
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

akretschmer
Erfahrener Benutzer
Beiträge: 7715
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Re: Check Contraint Verstoß mit Array

Beitrag von akretschmer »

ahh, ich glaube, Du suchst sowas hier:

Code: Alles auswählen

test=*# create table lebmitt(type text[], check (type <@ array['natürlich','milchsauer vergoren']));
CREATE TABLE
test=*# 
test=*# 
test=*# INSERT INTO lebmitt VALUES (array['natürlich']);
INSERT 0 1
test=*# INSERT INTO lebmitt VALUES (array['milchsauer vergoren']);
INSERT 0 1
test=*# INSERT INTO lebmitt VALUES (array['Bier']);
ERROR:  new row for relation "lebmitt" violates check constraint "lebmitt_type_check"
DETAIL:  Failing row contains ({Bier}).
test=*# 
hilft das weiter?
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

pogomips
Erfahrener Benutzer
Beiträge: 129
Registriert: Fr 18. Nov 2016, 09:55

Re: Check Contraint Verstoß mit Array

Beitrag von pogomips »

Abgesehen davon, dass es krass ist, was mit postgres alles geht, würde ich so ein Vorgehen nicht empfehlen.
Zumindest macht es bei den genannten Werten und der zu erwartenden Nutzung wahrscheinlich keinen Sinn.

Anhand der angegebenen Werte würde ich davon ausgehen, dass es neben den beiden genannten Beispielen weitere mögliche Werte gibt. Was erstmal okay ist.
Ich würde aber auch davon ausgehen, dass es übermorgen weitere derartige Werte gibt.
Diese Änderungen im inhaltlichen Bereich erfordern bei dem gewählten Vorgehen immer ein Alter Table Befehl. Alter Tables sind eine Änderung des Datenmodels und haben eine Reihe von Implikationen. Neben der Problematik, dass abhängige Objekte betroffen sein könnten, gibt es aber auch inhaltliche Probleme bei derartigen Constraints. Das Vorgehen wäre ein konzeptioneller Fehler.

Um noch anders deutlich zu machen, wo ich das Problem sehe:
Geht es bspw. um den Lebenszyklus einer Bestellung ['neu', 'bestätigt', 'kommisioniert', 'verschickt', 'angekommen', 'bewertet'], ist nicht zu erwarten, dass es häufige Änderungen gibt. Dies würde erst geschehen, bei neuen Workflows mit geänderten Implementierungen. Also ein legitimes Vorgehen und ein Gegenbeispiel zu der Aufgabenstellung des TE, wohlgemerkt, rein inhaltlich.

castorp
Erfahrener Benutzer
Beiträge: 1202
Registriert: Sa 27. Jun 2009, 22:24
Wohnort: Bayern

Re: Check Contraint Verstoß mit Array

Beitrag von castorp »

Ich würde das auch nicht mit einem Array machen, sondern sauber normalisieren. Wenn ein Lebensmittel wirklich mehr als einen Typ haben kann, dann sollte man das als sog. many-to-many Beziehung modellieren.
A SQL query walks into a bar and sees two tables. He walks up to them and says 'Can I join you?'

thorstein
Neuer Benutzer
Beiträge: 3
Registriert: So 9. Feb 2020, 15:02

Re: Check Contraint Verstoß mit Array

Beitrag von thorstein »

akretschmer hat geschrieben:
So 9. Feb 2020, 17:02
ahh, ich glaube, Du suchst sowas hier:

Code: Alles auswählen

test=*# create table lebmitt(type text[], check (type <@ array['natürlich','milchsauer vergoren']));
hilft das weiter?
Super, danke! Hab das entsprechend auf mein Problem umgemünzt:

Code: Alles auswählen

alter table lebmitt
add CONSTRAINT check_typ CHECK (typ::text[] <@ ARRAY[
  ..., 'natürlich', 'milchsauer vergoren', ...
  ]::text[]
);
Der ANY-Komperator ist wohl nur für genau ein Array-Element anwendbar.

thorstein
Neuer Benutzer
Beiträge: 3
Registriert: So 9. Feb 2020, 15:02

Re: Check Contraint Verstoß mit Array

Beitrag von thorstein »

pogomips hat geschrieben:
So 9. Feb 2020, 17:35
...
Diese Änderungen im inhaltlichen Bereich erfordern bei dem gewählten Vorgehen immer ein Alter Table Befehl. Alter Tables sind eine Änderung des Datenmodels und haben eine Reihe von Implikationen. Neben der Problematik, dass abhängige Objekte betroffen sein könnten, gibt es aber auch inhaltliche Probleme bei derartigen Constraints. Das Vorgehen wäre ein konzeptioneller Fehler.
...
Danke für den guten Hinweis. In meinem Fall bleibt es sehr beschränkt, überschaubar und ohne Anbindung an irgendwelche Prozesse/Applikationen - maximal eine Eingabe- und Suchmaske in Libre Base oder Access. Es gibt neben dem Typ noch eine weitere Spalte mit Kategorien, die ich auch mit einem Array abbilden wollte, da es ebenso reine Aufzählungen bzw. Schlagworte sind. Eine n:n-Relation aufzubauen, wäre überproportional.
Ich hoffe natürlich, dass man über die Array-Elemente bei Bedarf gut iterieren kann.

castorp
Erfahrener Benutzer
Beiträge: 1202
Registriert: Sa 27. Jun 2009, 22:24
Wohnort: Bayern

Re: Check Contraint Verstoß mit Array

Beitrag von castorp »

thorstein hat geschrieben:
Mo 10. Feb 2020, 03:52
Eine n:n-Relation aufzubauen, wäre überproportional.
Nein, wäre es nicht.
Es ist fast immer die bessere Strategie zuerst mit einem sauber normalisierten Modell anzufangen, und erst wenn es damit wirklich Probleme gibt, sich über de-Normalisierung Gedanken zu machen.
A SQL query walks into a bar and sees two tables. He walks up to them and says 'Can I join you?'

Antworten