Wie ordne ich true / false / unknown -1 / 0 / null ohne Wiederholung zu?

8

Ich arbeite gerade an einem Tool, das meinen Benutzern hilft, ihren SQL-Code nach SQL-Server 2005 zu portieren. Zu diesem Zweck analysiere ich das SQL in einen Syntaxbaum, analysiere es auf Konstrukte, die Aufmerksamkeit benötigen, modifiziere es und transformiere es zurück in T-SQL.

Auf etwas, das ich unterstützen möchte, ist die "bools sind Werte auch" Semantik anderer RDBMS. Zum Beispiel erlaubt mir MS-Access, select A.x and A.y as r from A zu schreiben, was in T-SQL unmöglich ist, weil:

  1. Spalten können keinen booleschen Typ haben (Spaltenwerte können nicht und nicht angegeben werden)
  2. Logische Prädikate können nicht verwendet werden, wenn Ausdrücke erwartet werden.

Daher konvertiert meine Transformationsroutine die obige Anweisung in folgendes:

%Vor%

Was funktioniert, ist aber ärgerlich, weil ich den logischen Ausdruck (der sehr komplex sein kann oder Unterabfragen enthalten kann) duplizieren muss, um zwischen true , false und unknown zu unterscheiden - letzteres soll map auf null. Also frage ich mich, ob die T-SQL-Profis hier einen besseren Weg kennen, dies zu erreichen?

UPDATE: Ich möchte darauf hinweisen, dass Lösungen, die versuchen, die Operanden in der Integer-Domäne zu halten, berücksichtigen müssen, dass einige Operanden logische Ausdrücke an der ersten Stelle sein können . Dies bedeutet, dass eine effiziente Lösung zur Umwandlung eines Bool in einen Wert immer noch erforderlich ist. Zum Beispiel:

%Vor%     
Nordic Mainframe 22.01.2011, 16:09
quelle

3 Antworten

1

Ich glaube nicht, dass es eine gute Antwort gibt, es ist wirklich eine Einschränkung von TSQL.

Sie könnten eine UDF für jeden booleschen Ausdruck erstellen, den Sie brauchen

%Vor%

verwendet über

%Vor%     
Scott Weinstein 22.01.2011 18:47
quelle
1

Boolesche Behandlung

Access scheint die Logik zu verwenden, die 2 Booleans gegeben hat

  • Beide müssen wahr sein, um wahr zurückzukommen
  • Entweder ist false falsch (unabhängig von Nullen)
  • Andernfalls gebe null zurück

Ich bin mir nicht sicher, ob andere DBMS (Oracle, DB2, PostgreSQL) mit bool + null umgehen, aber diese Antwort basiert auf der Bestimmung von Access (MySQL und SQLite stimmen zu). Die Tabelle der Ergebnisse ist unten dargestellt.

%Vor%

SQL Server Helper 1: Funktion für Boolean von jedem "Einzelwert"

In SQL Server im Allgemeinen füllt diese Funktion die Lücke für die fehlende any value as boolean -Funktionalität. Es gibt ein ternäres Ergebnis zurück, entweder 1/0 / null - 1 und 0 ist das SQL Server-Äquivalent von wahr / falsch (ohne tatsächlich boolesch zu sein).

%Vor%

Hinweis: Wenn Access als Ausgangspunkt verwendet wird, wird nur der numerische Wert 0 als FALSE ausgewertet Dies verwendet einige SQL Server-Tricks

  1. alles ist in varchar konvertierbar. Daher ist nur eine Funktion erforderlich, die Varchar-Eingaben benötigt.
  2. isnumeric ist nicht umfassend, '.' gibt 1 für isnumeric zurück, schlägt aber bei @v * 1.0 fehl, daher ist ein expliziter Test für LIKE [0-9]% 'erforderlich, um' isnumeric 'zu reparieren.
  3. @v * 1.0 wird benötigt, um einige arithmetische Probleme zu lösen. Wenn Sie die Zeichenfolge "1" in die Funktion ohne * 1.0 übergeben, wird
  4. bombardiert

Jetzt können wir die Funktion testen.

%Vor%

Sie können es jetzt sicher in einer Abfrage gegen ALLE EINZIGEN SPALTEN verwenden, z. B.

%Vor%

SQL Server-Hilfsprogramm 2: Funktion zum Zurückgeben des Ergebnisses von BOOL AND BOOL

Jetzt erstellt der nächste Teil dieselbe Wahrheitstabelle in SQL Server. Diese Abfrage zeigt Ihnen, wie zwei Bit-Spalten interagieren und die einfache CASE-Anweisung, um die gleiche Tabelle wie Access zu erstellen, und Ihre kompliziertere.

%Vor%

Dies wird leicht als Funktion ausgedrückt

%Vor%

SQL Server-Konvertierung anderer Ausdrücke (nicht eines einzelnen Werts)

Aufgrund fehlender Unterstützung für die Bit-from-Boolean-Konvertierung müssen Ausdrücke, die in SQL Server bereits [true / false / null] sind, in einer CASE-Anweisung wiederholt werden.

Ein Beispiel ist ein "true boolean" in SQL Server, der nicht das Ergebnis einer Spalte sein kann.

%Vor%

Muss als

ausgedrückt werden %Vor%

Aber wenn A kein skalarer Wert ist, sondern eine Unterabfrage wie (select sum(x)...) , dann wird, wie Sie sehen können, A zweimal vorkommen und zweimal in der CASE-Anweisung (wiederholt) ausgewertet werden.

ENDGÜLTIGER TEST Jetzt setzen wir alle Konvertierungsregeln in diesem langen Ausdruck

%Vor%

Dies führt zu SQL Server (Verkettung der beiden Funktionen und Verwendung von CASE)

%Vor%

Zugriff Bool or bool

Der Vollständigkeit halber ist hier die Wahrheitstabelle für Access bool OR bool . Im Wesentlichen ist es das Gegenteil von UND, also

  • Beide müssen falsch sein, um false
  • zurückzugeben
  • Entweder ist wahr wahr, wahr (unabhängig von Nullen)
  • Andernfalls gebe null zurück

Die SQL SERVER case-Anweisung wäre daher

%Vor%

(das Weglassen einer ELSE-Klausel ist beabsichtigt, da das Ergebnis NULL ist, wenn es weggelassen wird)

    
RichardTheKiwi 22.01.2011 21:04
quelle
-1

BEARBEITEN: Basierend auf zusätzlichen Informationen, die der Frage und den Kommentaren zu einer der vorgeschlagenen Antworten hinzugefügt wurden, formuliere ich diese Antwort:

Wenn Sie nach SQL Server portieren, würde ich erwarten, dass Sie die Daten auch an SQL Server-Typen anpassen. Wenn Sie ein boolesches Feld haben, werden True, False und Unknown auf 1, 0 und NULL als NULL-fähiges BIT-Feld abgebildet.

In diesem Sinne müssen Sie sich nur um die Umwandlung reiner boolescher Werte kümmern. Ausdrücke wie:

%Vor%

und:

%Vor%

sind bereits in einer praktikablen Form. Bedeutung, Aussagen wie:

%Vor%

und:

%Vor%

sind bereits korrekt. Sie müssen sich nur darum sorgen, dass "1" für "True" alleine nicht ausreicht. Daher können Sie "1" -Werte in boolesche Ausdrücke umwandeln, indem Sie testen, ob sie tatsächlich gleich "1" sind. Zum Beispiel:

%Vor%

ist das Äquivalent zu dem, was Sie vorher hatten:

%Vor%

Wenn Sie all dies zusammenfügen, sollten Sie einfach alle Instanzen reiner boolescher Werte des alten Codes in boolesche Ausdrücke in der Form "value = 1" übersetzen können, da eine 1 ein True erzeugt, 0 ein False , und NULL gibt Ihnen False.

JEDOCH besteht die wahre Komplexität darin, dass das Auswählen des Werts gegenüber dem Testen mit ihm über eine WHERE-Bedingung anders ist. Boolesche Ausdrücke werden in WHERE-Bedingungen korrekt ausgewertet, haben aber keine direkte Repräsentation für SELECT (besonders da NULL / Unknown nicht wirklich boolesch ist). Sie können also die "Value = 1" -Übersetzung in WHERE-Bedingungen verwenden, aber Sie benötigen weiterhin eine CASE-Anweisung, wenn Sie sie als Ergebnis AUSWÄHLEN möchten.

Wie bereits kurz erwähnt, ist NULL / Unknown nicht wirklich boolesch, es ist bedeutungslos zu versuchen, "NULL UND NULL" für eine WHERE-Bedingung in NULL zu konvertieren. Tatsächlich ist NULL wirklich FALSE, da es nicht als WAHR bestimmt werden kann. Auch dies kann für Ihre Zwecke in einer SELECT-Anweisung anders sein. Dies ist wiederum der Grund, warum die CASE-Anweisung dort Ihre einzige Wahl ist.

    
Solomon Rutzky 22.01.2011 19:18
quelle