Wie halte ich NULL auseinander?

Hahnematz

Neuer Benutzer
Beiträge
4
Hallo,
ich befinde mich gerade in meiner Ausbildung und bin heute in einer Übung auf ein für mich interessantes Problem gestoßen, was ich im nachhinein daheim probiert habe, aber leider nicht selbst gelöst bekam.

Und zwar folgender Umstand:

Ich habe eine Tabelle der Form: GUID(PK) | ZeigerGUID | Datum | Wert
Datentypen der Spalten: uniqueid. not null | uniqueid. not null | datetime not null | varchar(50) null
In dieser Tabelle wird gespeichert, welcher Prozess (ZeigerGUID) zu welchem Datum, welchen Wert hat.

Nun hätte ich gerne den Wert zu einem bestimmten Datum. Die Abfrage hierbei ist folglich:

SELECT Wert
FROM Tabelle
WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert

Dieses Weise ich einer Variablen @Wert zu. Und hier beginnt mein Problem:
Die Variable @Wert kann den Wert NULL erhalten, wenn dies entweder in der Wertspalte am angegebenen Datum so steht, oder es zu einem bestimmten Datum erst gar keine Einträge gibt. Wie unterscheidet man nun gekonnt ob das nun ein genulltes Wertfeld war oder eine Abfrage ohne Ergebnisse?

Eine Variante die grob funktionierte, mich aber in keinster Weise zufriedenstellte, war ein
SELECT Count(*)
FROM Tabelle
WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert
einer weiteren Variablen zu zuweisen und dann zu entscheiden: bei 0 wars die Abfrage, bei 1 der Wert. Doch irgendwie wirkt diese Lösung unsauber.

Da ich mich verbessern möchte, habt ihr hier vielleicht einen Rat oder Stupser in eine bessere Richtung für mich?

Mit freundlichem Gruße
der Hahnematz
 
Werbung:
Eine Variante die grob funktionierte, mich aber in keinster Weise zufriedenstellte, war ein
SELECT Count(*)
FROM Tabelle
WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert
einer weiteren Variablen zu zuweisen und dann zu entscheiden: bei 0 wars die Abfrage, bei 1 der Wert. Doch irgendwie wirkt diese Lösung unsauber.

Da ich mich verbessern möchte, habt ihr hier vielleicht einen Rat oder Stupser in eine bessere Richtung für mich?

Mit freundlichem Gruße
der Hahnematz

De Ansatz ist schon okay. Je nach Applikation, mit der du das machst, hast Du aber auch eine Info, wie groß das Resultset ist.

Code:
test=*# select * from hahnematz ;
 id | zeiger | val
----+--------+-----
  1 |  2 |  3
  |  |  4
  3 |  3 |  4
  5 |  5 |
(4 rows)

Time: 0,149 ms
test=*# select val from hahnematz where id = 5 and zeiger = 5;
 val
-----

(1 row)

Time: 0,201 ms
test=*# select val from hahnematz where id = 5 and zeiger = 6;
 val
-----
(0 rows)

Time: 0,191 ms

Beacht ein den 2 letzten Abfragen die Aussage über die Anzahl Rows.
 
Ich hab jetzt noch ein wenig versucht das gezeigte nach zu stellen, aber dieses *# ist mir bisher gänzlich unbekannt und ich finde leider auch nichts darüber. Was hat es damit auf sich?

Mit freundlichem Gruße
der Hahnematz
 
Ich hab jetzt noch ein wenig versucht das gezeigte nach zu stellen, aber dieses *# ist mir bisher gänzlich unbekannt und ich finde leider auch nichts darüber. Was hat es damit auf sich?

Ich mußte erst mal überlegen, was Du meinst ;-)

Das ist der Prompt der Datenbank. Dahinter kann man seine SQL-Befehle schreiben.

Code:
psql test
Timing is on.
psql (9.3.0)
Type "help" for help.

test=# select now();
  now
-------------------------------
 2013-11-19 07:56:18.828318+01
(1 row)

Time: 68,608 ms
test=*#

Ich hab den bei mir noch ge-pimpt: =# bedeutet: nicht in einer Transaktion, =*#: ich bin in einer Transaktion, ich habe AUTOCOMMIT=OFF in meiner Konfiguration.
 
Die Abfrage

SELECT Wert
FROM Tabelle
WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert

liefert den Returncode "NOTFOUND", wenn die Abfrage ohne Ergebnis ist. Ansonsten liefert sie den "Wert" (dieser kann auch NULL sein).
 
Zuletzt bearbeitet:
Also um mal auf das Problem einzugehen, zwischen NULL und NULL kann man zunächst mal nicht unterscheiden. Natürlich gibts einige Wege das mit Abfragen zu lösen, ich versuche mich mal an alternativen Varianten. Was Sinn macht muss man dann im jeweiligen Anwendungsfall entscheiden.
Code:
IF EXISTS (    SELECT    1
            FROM    Tabelle
            WHERE    ZeigerGUID=IrgendEinProzess AND Datum=Datumswert
BEGIN
    DECLARE    @Wert UNIQUEIDENTIFIER
    SET        @Wert = (    SELECT    Wert
                        FROM    Tabelle
                        WHERE    ZeigerGUID=IrgendEinProzess AND Datum=Datumswert )
END
ELSE
BEGIN
    SELECT    'Fehler' AS Fehler
END
EXISTS ist gut um das Vorhandensein von Daten zu prüfen. Ist natürlich mindestens eine weitere Abfrage.
Code:
DECLARE    @Wert UNIQUEIDENTIFIER,
        @isnull BIT

SELECT    @Wert = Wert,
        @isnull = 1
FROM    Tabelle
WHERE    ZeigerGUID=IrgendEinProzess AND Datum=Datumswert
In diesem Fall hätten wir eine Variable @isnull die auf 1 steht wenn der Wert aus der Tabelle NULL ist. Wenn es keinen Wert in der Tabelle gibt müssten eigentlich beide Variablen NULL sein.

Dann gäbe es auch noch isnull() als Funktion mit der man einen standard Wert vergeben könnte, das hilft dir aber nicht beim Unterscheiden.
 
Vielen Dank für eure Hilfe, das hat mich echt weiter gebracht :)
Da es auch mit EXISTS, wie von ukulele gezeigt, zu einer weiteren Abfrage kommt habe ich mir meinen ersten Ansatz nochmal hergenommen und in eine Bedingung verpackt die mir erfolgreich alle 3 Zustände liefert (Wert/NULL-Wert/leereErgebnismenge). Selbiges auch mit EXISTS probiert und funktioniert auch wie gewollt.

Vielen Dank nochmals, ihr seid Spitze! :)

Mit freundlichem Gruße
der Hahnematz
 
Das ist die Abfrag für die Unterscheidung ob es nun ein NULL-Wert ist oder keine Ergebnismenge zurückgegeben wurde.
Da drum herum liegt nurnoch die Abfrage für @Wert NOT NULL weil das meine normale Routine ist :)

Code:
@Wert = (SELECT Wert FROM Tabelle WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert)

IF (@Wert IS NULL AND EXSISTS(SELECT Wert FROM TABELLE WHERE ZeigerGUID=IrgendEinProzess AND Datum=Datumswert))
-- Wert ist NULL aber der Datensatz existiert
ELSE
-- leere Ergebnismenge

Falls noch Anregungen vorhanden sind bin ich ganz Ohr!

Mit freundlichem Gruße
der Hahnematz
 
Werbung:
Zurück
Oben