So erstellen Sie eine Ansichtsspalte NICHT NULL

84

Ich versuche, eine Ansicht zu erstellen, in der eine Spalte nur wahr oder falsch sein soll. Es scheint jedoch, dass SQL Server (2008), egal was ich tue, glaubt, dass meine Bitspalte irgendwie null sein kann.

Ich habe eine Tabelle namens "Produkt" mit der Spalte "Status" INT, NULL. In einer Ansicht möchte ich für jede Zeile in Product eine Zeile zurückgeben, wobei eine BIT-Spalte auf true gesetzt ist, wenn die Product.Status-Spalte gleich 3 ist. Andernfalls sollte das Bitfeld false sein.

Beispiel SQL

SELECT CAST( CASE ISNULL(Status, 0)  
               WHEN 3 THEN 1  
               ELSE 0  
             END AS bit) AS HasStatus  
FROM dbo.Product  

Wenn ich diese Abfrage als Ansicht speichere und die Spalten im Objekt-Explorer betrachte, wird die Spalte HasStatus auf gesetzt BIT, NULL. Aber es sollte niemals NULL sein. Gibt es einen magischen SQL Trick , den ich verwenden kann , um diese Spalte zu zwingen , zu sein NOT NULL.

Beachten Sie, dass, wenn ich das um das CAST()herum entferne CASE, die Spalte korrekt als festgelegt ist NOT NULL, aber dann der Spaltentyp auf festgelegt ist INT, was nicht das ist, was ich will. Ich möchte, dass es so ist BIT. :-)

René
quelle

Antworten:

150

Sie können erreichen, was Sie wollen, indem Sie Ihre Abfrage ein wenig neu anordnen. Der Trick ist, dass das ISNULLaußen sein muss, bevor SQL Server versteht, dass der resultierende Wert niemals sein kann NULL.

SELECT ISNULL(CAST(
    CASE Status
        WHEN 3 THEN 1  
        ELSE 0  
    END AS bit), 0) AS HasStatus  
FROM dbo.Product  

Ein Grund, warum ich dies tatsächlich nützlich finde, ist die Verwendung eines ORM, und Sie möchten nicht, dass der resultierende Wert einem nullbaren Typ zugeordnet wird. Es kann die Sache rundum einfacher machen, wenn Ihre Anwendung den Wert als niemals möglicherweise null ansieht. Dann müssen Sie keinen Code schreiben, um Nullausnahmen usw. zu behandeln.

RedFilter
quelle
@Gunder: Keine Sorge, es ist eigentlich ein bisschen arkan. Dies ist auch praktisch, wenn Sie eine berechnete Bitspalte in einer Tabelle erstellen und möchten, dass das Ergebnis nicht nullwertfähig ist.
RedFilter
8
Ich brauchte etwas ähnliches, und ich fand , dass COALESCE()keine Arbeit haben, die Sie tatsächlich haben zu verwendenISNULL()
EvilBob22
@ EvilBob22 Das ist seltsam, weil sowohl COALESCE als auch ISNULL NULL zurückgeben können. Nur eine Compiler-Eigenart, denke ich.
RedFilter
1
Dies ist eine Milliarde Mal, um EntityFramework dazu zu bringen, einen Schlüssel abzuleiten, wenn man normalerweise nicht abgeleitet wird.
Erik
3

Zu Ihrer Information: Wenn Personen auf diese Nachricht stoßen, kann das Hinzufügen von ISNULL () an der Außenseite des Cast / Convert den Optimierer in Ihrer Ansicht durcheinander bringen.

Wir hatten 2 Tabellen mit demselben Wert wie ein Indexschlüssel, aber mit unterschiedlichen numerischen Genauigkeiten (schlecht, ich weiß), und unsere Ansicht verband sie, um das Endergebnis zu erzielen. Unser Middleware-Code suchte jedoch nach einem bestimmten Datentyp, und in der Ansicht wurde CONVERT () um die Spalte zurückgegeben

Ich bemerkte, wie das OP, dass die Spaltenbeschreibungen des Ansichtsergebnisses es als nullwert definierten und ich dachte, es ist ein Primär- / Fremdschlüssel für 2 Tabellen; Warum sollte das Ergebnis als nullwert definiert werden?

Ich habe diesen Beitrag gefunden, ISNULL () um die Spalte geworfen und voila - nicht mehr nullbar.

Das Problem war, dass die Leistung der Ansicht direkt auf die Toilette ging, als eine Abfrage in dieser Spalte gefiltert wurde.

Aus irgendeinem Grund hat ein explizites CONVERT () in der Ergebnisspalte der Ansicht den Optimierer nicht durcheinander gebracht (das musste es aufgrund der unterschiedlichen Präzisionen sowieso tun), aber das Hinzufügen eines redundanten ISNULL () - Wrappers hat es in einem großen Fall getan Weg.

user1664043
quelle
Könnten Sie CONVERT()bitte in einem Beispiel die Lösung zeigen, wie Sie die Nicht-Nullfähigkeit sicherstellen / anzeigen können ?
ODER Mapper
1
Hallo ODER - Entschuldigung, ich habe das eine Weile nicht gesehen. Hier ist ein Beispiel. Wenn Sie CONVERT (BIT, U.RETIRED), 0) AS Retired in Ihrer Ansicht haben und beispielsweise ein Byte oder eine int-Spalte in ein Bit / Bool verwandeln, wird es nullwertfähig. Sie können diese Spalte in Ihrer Ansicht nicht nullbar machen, indem Sie sie durch ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Retired ersetzen. Wenn U.RETIRED zum Starten nicht null war, ändert es funktional nichts außer der Spalte in der Ansicht. WARNUNG: ISNULL () kann die Abfrageoptimierung und die Auswahl der Indikatoren beeinträchtigen.
user1664043
-3

In einer Select-Anweisung können Sie lediglich die Daten steuern, die das Datenbankmodul als Client an Sie sendet. Die select-Anweisung hat keine Auswirkung auf die Struktur der zugrunde liegenden Tabelle. Um die Tabellenstruktur zu ändern, müssen Sie eine Alter Table-Anweisung ausführen.

  1. Stellen Sie zunächst sicher, dass sich in diesem Bitfeld in der Tabelle derzeit keine Nullen befinden
  2. Führen Sie dann die folgende ddl-Anweisung aus: Alter Table dbo.Product Alter column status bit not null

Wenn Sie nur versuchen, die Ausgabe der Ansicht zu steuern, ist das, was Sie tun, ausreichend. Ihre Syntax garantiert, dass die Ausgabe der HasStatus-Spalte in der Views-Ergebnismenge tatsächlich niemals null ist. Es wird immer entweder Bitwert = 1 oder Bitwert = 0 sein. Machen Sie sich keine Sorgen, was der Objekt-Explorer sagt ...

Charles Bretana
quelle
6
Ich möchte die Tabellenspalte nicht ändern. Die Spalte ist als Ganzzahlspalte definiert, die Null zulässt. Dies entspricht unserer Spezifikation. Aber ich brauche eine Ansicht, die eine Spalte mit einem Bitfeld zurückgibt, das nicht null sein kann. Es reicht nicht aus, dass ich weiß, dass es nicht null sein kann, die Spalte muss NICHT NULL sein, damit sie in unserem ORM korrekt zugeordnet wird.
René