Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi MS-Access 2016: VARCHAR mit Inhalt "" oder NULL (https://www.delphipraxis.net/204363-ms-access-2016-varchar-mit-inhalt-oder-null.html)

berens 22. Mai 2020 16:11

Datenbank: MS Access • Version: 2016 • Zugriff über: TAdoConnection

MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,
ich habe ein Problem mit einer Abfrage in meiner Anwendung. Ich konnte es soweit eingrenzen, dass das Problem nicht innerhalb von meinem Programm oder Delphi besteht, sondern alleine in der MS-Datenbank (.mdb), die wir verwenden [müssen]:

Ich benötige alle Zeilen einer Tabelle, bei denen [der String in] MyField leer ist. MyField ist ein String, hier konkret in dieser .mdb-Datei ein "Kurzer Text" (via SQ-Statement VARCHAR(255) angelegt). Der Standardwert soll leer sein, also "".

Über die SuFu hier im Forum konnte ich schon ermitteln, dass es für eine vergleichbare Abfrage ein riesen Unterschied ist, ob ein Feld den "Systemwert" NULL gespeichert hat, oder den leeren String "". Eine Abfrage, für Zeilen in denen bei MyField kein sichtbarer Text drinnen steht, scheint also nicht so ganz trivial.

Theoretisch müsste diese Abfrage immer die richtigen Werte liefern:
Code:
SELECT *
FROM Tabelle1
WHERE (((Myfield) Is Null)) or (MyField="");
Aber Access verhält sich heute sehr merkwürdig und ich traue dem Braten nicht. Auch besteht natürlich die Gefahr, dass dieser Filter an mehreren Stellen im Quelltext benötigt wird, und bei komplexen Ausdrücken nun doch irgendwas schief läuft, wenn ich da einfach die alte Abfrage MyField <> "" durch die o.g. ersetze...

Für vergleichbare Fälle lasse ich beim Programmstart eine Logikprüfung über meine Tabellen laufen (z.B. dass eine Warnmeldung ausgegeben wird, sollte der Zeitpunkt für das Ende ein Termins einmal vor dem Startzeitpunkt liegen etc.), wo ich nun auch gerne alle Einträge mit NULL in MyField auf "" setzen würde (=leeren String, aber halt nicht NULL).

Meine Abfrage dafür lautet.
Code:
UPDATE Tabelle1 SET MyField = ""
WHERE (MyField Is Null);
Diese habe ich zu Testzwecken in Access direkt ausgeführt und keine Fehlermeldung erhalten.
Leider gibt die Abfrage
Code:
SELECT *
FROM Tabelle1
WHERE (Myfield Is Null)
nun immer noch Datensätze zurück, die vorherige Änderungsabfrage war also scheinbar nicht erfolgreich.

Was mache ich falsch, was muss ich anders machen?

Kann ich evtl. die Einstellungen für die Spalte MyField (siehe Anhang) verändern, dass NULL automatisch als identisch mit "" interpretiert wird?
Scheinbar kann der Wert "Leere Zeichenfolge" angeben, ob eine leere Zeichenfolge gültig ist (Leerer String oder NULL???). Ich kann die verlinkte Dokumentation aber nicht soweit interpretieren, ob -wenn ich diesen Wert auf "Nein" stelle, dann alles NULL als "" interpretiert wird? Es gibt noch die Eigenschaft "Required" (Eingabe erforderlich), aber ich denke fast, diese Werte spielen nur innerhalb der Access-GUI eine Rolle?

Vielen Dank für Tips!

stifflersmom 22. Mai 2020 16:16

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Kennt Access coalesce?

Dann wäre das eine Möglicghekit, dei Abfrage sicher auszuführen:

Code:
SELECT *
FROM Tabelle1
WHERE COALESCE(Myfield,'') ="";

berens 22. Mai 2020 16:21

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Nope.

Zitat:

Undefinierte Funktion "COALESCE" in Ausdruck.

stifflersmom 22. Mai 2020 16:42

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Hier wird NZ als Möglichkeit beschrieben:
https://www.techonthenet.com/access/...dvanced/nz.php

Dann müsste das so gehen:

Code:
SELECT *
FROM Tabelle1
WHERE Nz(Myfield,'') ="";

himitsu 22. Mai 2020 16:57

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Sind im Access " und ' wirklich das Selbe?


Access hat aber nicht zufällig was drin, dass aus Leerstrings ein NULL macht, bzw. andersrum?

PS: In dem Bild steht bei Default/Standardwert was von "".
Aber eigentlich dachte ich der Default wird in allen DBMS nur dann verwendet, wenn man ein INSERT ausführt, und dabei dieses Feld nicht übergibt.

In PgDAC gibt es z.B. eine Option, die sowas bei einem Post macht. (zwar werden hier nur im DataSet die TField im BeforePost auf NULL gesetzt und nicht bei einem direkten UPDATE-Statement), aber vielleicht gibt es im Access sowas auch direkt in der Datenbank.



Bei Required/Erforderlich = True sollte jede explizite Zuweisung von NULL (und ein fehlendes DEFAULT beim INSERT) zu einer Fehlermeldung führen.
Wenn es nie NULL sein soll, wieso aktivierst du das dann nicht?

berens 22. Mai 2020 18:07

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Danke, @stifflersmom, das liefert [auch?] die Zeilen zurück, die NULL sind. Die Beschreibung auf der verlinkten Website ist schlüssig.
Code:
SELECT *
FROM Tabelle1
WHERE Nz(Myfield,'') ="";
Leider kann ich mit Access gerade keinen Eintrag erzeugen, der nur leeren Text drinnen hat, aber kein Null, aber ich hoffe einfach mal, wenn das NZ von vielen Leuten verwendet wird, dass es da auch zuverlässig arbeitet :stupid: . Danke soweit.

@himitsu
> In dem Bild steht bei Default/Standardwert was von "".
Ja, das hat mich auch gewundert. Natürlich steht in meinem Quelltext:
Delphi-Quellcode:
q.SQL.Add('ALTER TABLE Tabelle1 ADD Myfield VARCHAR(255) DEFAULT "";');
Aber dass der das soooo wörtlich nimmt...
Es kann natürlich auch sein, dass die Zeilen bei/nach der Anpassung der Tabelle einmalig einen "leeren String" haben (z.B. \#0 oder wie auch immer das Zeichen dafür ist), und beim Abspeichern durch mein Programm, wenn der Wert "" dann über eine interne Routine den o.g. \#0 bekommen oder so.

> Wenn es nie NULL sein soll, wieso aktivierst du das dann nicht?
Eine fachlich richtige Antwort kann ich die hierfür nicht geben, dafür weiß ich, das Du ein x-Mal besserer Programmierer bist als ich; hast mir ja schon oft genug geholfen. Es gibt hier nur die "ehrliche" Antwort: aus Faulheit UND Unwissenheit. Long story short, bevor ich hier zu weit abdrifte: Ich habe mehrere Module die Einträge in dieser "Tabelle1" anlegen können. Diese sind nicht miteinander verkoppelt - was auch so bleiben soll(te). Wenn Modul1 -was den Wert "MyField" nicht kennt- nun eine Zeile schreibt, und NULL nicht mehr zugelassen ist, gibt es -denke ich mal- beim Post 'ne Exception. Modul1 kennt aber das Feld nicht. Ich müsste alle Module anpassen um (zusätzlich) ein Feld zu initialisieren, was in diesen Modulen 0% Relevanz hat. Mir als Mensch ist das echt sowas von egal ob da NULL oder "" drin steht, nur die Abfrage muss mir zuverlässig zurückgeben "ob da in dem Feld menschenlesbare Zeichen drinen sind, oder nicht". Hier ist die angepasste Abfrage von @stifflersmom einfacher an 7-8 Stellen einzupflegen, als in jedem Modul -imo "unnötigerweise"- das Feld "MyField" jedes Mal mit abspeichern zu lassen, NUR damit es keine Exception gibt. Natürlich wäre dein vorgeschlagenes Verfahren das Richtige - ToDo-Liste und Terminierungen sagen aber: geht nicht, nicht die "einfache" Lösung. Nicht professionell, aber ich kann mich leider nicht verreißen... Und ja: da muss von Grund auf eine andere Struktur rein. Stichwort: Historisch gewachsen. :?

Ich hoffe, dass die NZ Funktion alles perfekt abdeckt, ich denke, damit komme ich für den Moment ausreichend weiter.
Vielen Dank allen Antwortern :thumb:, Thema beendet.

himitsu 22. Mai 2020 18:56

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
SQL-Code:
CREATE TABLE mytable (
  field1 VARCHAR(255),
  field2 VARCHAR(255) DEFAULT '',
  field3 VARCHAR(255) NOT NULL,
  field4 VARCHAR(255) NOT NULL DEFAULT ''
);

-- fehlt field3/4, dann wird dort der DEFAULT genommen
-- field3 muß also immer übergeben werden, da es keinen DEFAULT hat und somit einen Wert benötigt
INSERT INTO mytable (field1, field3) VALUES ...;

-- hier müssen alle Felder übergeben werden und bei field3/4 dürfen keine NULL drin stehen
INSERT INTO mytable VALUES ...;

-- bei einigen DBMS kann man im INSERT und UPDATE auch "DEFAULT" angeben, selbst wenn das Feld angegeben wird
-- bei field4 ein NULL zu übergeben knallt natürlich
INSERT INTO mytable (field3, field4) VALUES ('aa', DEFAULT);

-- hier in einem Dataset.Insert, werden field2/3 niemals übergeben (fehlen im automatisch generierten INSERT und UPDATE)
-- die field1 und field4 werden nach einem Dataset.Insert nur übergeben, wenn dort etwas eingetragen wurde (siehe fehlen dann also auch und bekommen ihren DEFAULT, wenn vorhanden)
-- bei field3 wird es also knallen, da es NOT NULL ist und keinen DEFAULT hat
-- field4 wird beim Dataset.Insert nicht knallen, da es im automatischen INSERT fehlt, wenn dort nichts zugewiesen wurde, und somit der DEFUALT benutzt wird
-- aber wird beim Dataset.Edit (UPDATE) das field4 auf NULL gesetzt (und vorher war es nicht NULL), dann knallt das natürlich auch
SELECT field1, field4 FROM mytable;
Wer ein Feld mit NUL NULL mit DEFAULT nicht kennt, dem ist das also im Normalfall egal.

ABER, wenn hier
SQL-Code:
SELECT *
verwendet wird und das Dataset auf die TField.Requiered (NOT NULL) reagiert (dieses Required von der DB füllen lässt),
dann gibt es ein Problem, denn auf den DEFAULT reagieren viele DB-Komponenten nicht (weil sie es nicht kennen und nicht wissen, dass es zwar Required ist, aber spätestens in der DB doch einen Wert bekommen kann).
Ebenso ist es mit NOT NULL, wo der Wert im Trigger gefüllt wird. TDataSet weiß nichts davon und reagiert entsprechend auf das Requiered.
Bei uns wird aus Diesem und einem anderen Grund im Dataset.AfterInsert der DEFAULT-Wert aus der DB abgerufen und eingefügt.
* einmal gibt es dann nach DataSet.Insert beim Post keine Fehlermeldung "Feld muß gefüllt sein"
* und der Benutzer sieht auch sofort, wo bereits Default-Daten vorhanden sind, die ja sonst eigentlich erstmal leer sind und erst beim Speichern (Post) von der Datenbank gefüllt werden.

berens 22. Mai 2020 19:14

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
:shock: Dass "NOT NULL" mit "DEFAULT ''" kombiniert werden kann, war jetzt zu offensichtlich (Wald und Bäume und so ...). Das löst natürlich alle Probleme. Ich muss jetzt natürlich nochmal irgendwie mit "ALTER TABLE" die bestehenden Datenbanken/Tabellen der Kunden zu aktualisieren.
Delphi-Quellcode:
field4 VARCHAR(255) NOT NULL DEFAULT ''
Danke nochmal. :thumb:

Delphi.Narium 23. Mai 2020 09:20

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Alter table ändert aber keine vorhandenen Werte. Ein nachträgliches per Alter Table ergänztes Default '' führt nicht dazu, dass bis dahin mit NULL gefüllte Werte nun den Defaultwert erhalten. Hier musst Du ggfls. nochmal per Update "hinterhergehen".

DasWolf 25. Mai 2020 11:57

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Zitat:

Zitat von berens (Beitrag 1465080)
:shock: Dass "NOT NULL" mit "DEFAULT ''" kombiniert werden kann, war jetzt zu offensichtlich (Wald und Bäume und so ...). Das löst natürlich alle Probleme. Ich muss jetzt natürlich nochmal irgendwie mit "ALTER TABLE" die bestehenden Datenbanken/Tabellen der Kunden zu aktualisieren.
Delphi-Quellcode:
field4 VARCHAR(255) NOT NULL DEFAULT ''
Danke nochmal. :thumb:

:pale: Das ist ein absolutes No-Go!
Felder, die kein Primary-Key oder dergleichen sind, werden nicht über die Datenbank als NOT NULL definiert. Das wird über die Software geregelt.
Diesen Fehler habe ich einmal gemacht. Seitdem nie wieder.

jobo 27. Mai 2020 18:06

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
Zitat:

Zitat von DasWolf (Beitrag 1465208)
Zitat:

Zitat von berens (Beitrag 1465080)
:shock: Dass "NOT NULL" mit "DEFAULT ''" kombiniert werden kann, war jetzt zu offensichtlich (Wald und Bäume und so ...). Das löst natürlich alle Probleme. Ich muss jetzt natürlich nochmal irgendwie mit "ALTER TABLE" die bestehenden Datenbanken/Tabellen der Kunden zu aktualisieren.
Delphi-Quellcode:
field4 VARCHAR(255) NOT NULL DEFAULT ''
Danke nochmal. :thumb:

:pale: Das ist ein absolutes No-Go!
Felder, die kein Primary-Key oder dergleichen sind, werden nicht über die Datenbank als NOT NULL definiert. Das wird über die Software geregelt.
Diesen Fehler habe ich einmal gemacht. Seitdem nie wieder.

Bei Access lohnt ja kein Streit, aber:
Vielleicht bist Du so freundlich und erklärst auch, wie sich der Fehler begründet?
Hat jemand deshalb mit dem Baseballschläger Dein Auto zertrümmert oder gibt es eine fachliche Erklärung, z.B. eine Access spezifische?

Ansonsten gebe ich für alle DB mit Feldern not null default <whatever-except-null> ein absolutes Go!

p80286 27. Mai 2020 20:22

AW: MS-Access 2016: VARCHAR mit Inhalt "" oder NULL
 
wahrscheinlich ist er über < > und ähnliches und die Unvereinbarkeit mit NULL gestolpert.

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz