2010-02-24 12 views
65

Ich versuche, eine Sicht zu erstellen, in der eine Spalte nur wahr oder falsch sein soll. Es scheint jedoch, dass egal, was ich mache, SQL Server (2008) glaubt, dass meine Bitspalte irgendwie null sein kann.So erstellen Sie eine View-Spalte NOT NULL

Ich habe eine Tabelle namens "Produkt" mit der Spalte "Status", die INT, NULL ist. In einer Ansicht möchte ich eine Zeile für jede Zeile in Product zurückgeben, wobei eine BIT-Spalte auf "true" gesetzt wird, wenn die Product.Status-Spalte gleich 3 ist, andernfalls sollte das Bitfeld falsch 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 speichern und an den Spalten im Objekt-Explorer suchen, die Spalte HasStatus auf BIT, NULL gesetzt. Aber es sollte nie NULL sein. Gibt es einen magischen SQL-Trick, den ich verwenden kann, um diese Spalte zu zwingen, NOT NULL zu sein.

Beachten Sie, dass, wenn ich die CAST() um die CASE zu entfernen, wird die Spalte richtig eingestellt als NOT NULL, aber dann der Typ der Spalte wird auf INT, das nicht das, was ich will. Ich möchte, dass es BIT ist. :-)

+0

@Gunder: +1, Willkommen bei StackOverflow. Ich habe deine Frage formatiert, sieh sie dir an, um etwas über Formatierung herauszufinden :) –

+0

Ahh, ich brauchte noch einen Zeilenumbruch vor dem Code. Vielen Dank. :-) –

Antwort

119

Sie können erreichen, was Sie wollen, indem Sie Ihre Abfrage ein wenig neu anordnen. Der Trick ist, dass die ISNULL auf der Außenseite sein muss, bevor SQL Server verstehen wird, dass der resultierende Wert nie NULL sein kann.

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 nützlich tatsächlich finden ist, wenn ein ORM verwenden und Sie wollen nicht den resultierenden Wert auf einen Nullable Types abgebildet. Es kann die Dinge rundherum einfacher machen, wenn Ihre Anwendung den Wert als null wahrnimmt. Dann müssen Sie keinen Code schreiben, um Null-Exceptions usw. zu behandeln.

+0

Das funktioniert! - Ich danke dir sehr! - Ich bin ein bisschen beschämt, dass ich das nicht zuerst probiert habe. :-) –

+0

@Gunder: keine Sorge, es ist eigentlich ein bisschen geheimnisvoll. Dies ist auch praktisch, wenn Sie eine berechnete Bitspalte in einer Tabelle erstellen und das Ergebnis nicht nullfähig sein soll. – RedFilter

+4

Ich brauchte etwas Ähnliches, und ich fand, dass 'COALESCE()' nicht funktionierte, du musst * ISNULL() verwenden ' – EvilBob22

-1

Alles, was Sie in einer Select-Anweisung tun können, ist die Kontrolle der Daten, die die Datenbank-Engine Ihnen als Client sendet. Die SELECT-Anweisung hat keine Auswirkungen auf die Struktur der zugrunde liegenden Tabelle. Um die Tabellenstruktur zu ändern, müssen Sie eine Alter Table-Anweisung ausführen.

  1. Zuerst stellen Sie sicher, dass es derzeit keine NULL-Werte in diesem Bit-Feld in der Tabelle
  2. dann die folgende DDL-Anweisung ausführen: Alter Table dbo.Product Alter column status bit not null

Wenn OTOH, alles, was Sie zu tun versuchen ist die Ausgabe der Ansicht steuern, dann was Sie tun, ist ausreichend. Ihre Syntax garantiert, dass die Ausgabe der HasStatus-Spalte in den Views-Resultsets niemals null ist. Es wird immer entweder Bitwert = 1 oder Bitwert = 0 sein. Keine Sorge, was der Objekt Explorer sagt ...

+5

Ich möchte die Tabellenspalte nicht ändern. Die Spalte ist als Integer-Spalte definiert, die null zulässt. Das passt zu unserer Spezifikation. Aber ich brauche eine Ansicht, die eine Spalte mit einem Bitfeld zurückgibt, das nicht null sein kann. Es ist nicht ausreichend, dass ich weiß, dass es nicht Null sein kann, die Spalte muss NICHT NULL sein, damit sie in unserem ORM korrekt zugeordnet wird. –

0

Dies ist der Code, den ich verwende, wird die ID-Spalte NOT NULL und alle anderen NULL machen. Sie müssen die Bit- oder Varchar-Spalte umwandeln und die int-Spalte mit NULL vergleichen.

CREATE TABLE [dbo].[aTestTable](
    [ID] [int] NOT NULL, 
    [varcharCol] [varchar](50) NOT NULL, 
    [nullvarcharCol] [varchar](50) NULL, 
    [bitCol] [bit] NOT NULL, 
    [nullbitCol] [bit] NULL, 
    [intCol] [int] NOT NULL, 
    [nullintCol] [int] NULL, 
CONSTRAINT [PK_aTestTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


CREATE VIEW [dbo].[aTestView] 
AS 
SELECT ID , 
     NULLIF(varcharCol , '') AS varcharCol , 
     NULLIF(CAST(varcharCol AS VARCHAR), null) AS varcharCol1, --better 
     nullvarcharCol , 
     NULLIF(CAST(bitCol AS INT), null) AS bitCol , 
     nullbitCol , 
     NULLIF(CAST(intCol AS INT), NULL) AS intCol , 
     nullintCol 
FROM dbo.aTestTable 


Sample Data: 

ID varcharCol nullvarcharCol bitCol nullbitCol intCol nullintCol 
1 1 1 1 1 1 1 
2 0 0 0 0 0 0 
3 0 NULL 0 NULL 0 NULL 
4 a a 1 1 2 2 

hth

3

FYI, für die Menschen in dieser Nachricht läuft, Hinzufügen der ISNULL() um die Außenseite des gegossenen/convert den Optimierer auf Ihrer Ansicht kann vermasseln.

Wir hatten 2 Tabellen mit dem gleichen Wert wie ein Indexschlüssel, aber mit Typen unterschiedlicher numerischer Genauigkeit (schlecht, ich weiß) und unsere Ansicht wurde beigefügt, um das Endergebnis zu produzieren. Aber unser Middleware-Code suchte nach einem bestimmten Datentyp, und die View hatte eine CONVERT() um die zurückgegebene Spalte

Ich bemerkte, wie das OP tat, dass die Spaltenbeschreiber des View-Ergebnis definiert es als Nullable und ich dachte, Es ist ein Primär-/Fremdschlüssel an 2 Tischen; Warum sollten wir das Ergebnis als Nullable definieren?

Ich fand diesen Beitrag, warf ISNULL() um die Spalte und voila - nicht mehr nullfähig.

Problem war die Leistung der Ansicht ging direkt auf die Toilette, wenn eine Abfrage über diese Spalte gefiltert.

Aus irgendeinem Grund vermasselte eine explizite CONVERT() in der Ergebnisspalte der Ansicht den Optimierer nicht (dies musste er wegen der unterschiedlichen Genauigkeiten trotzdem tun), aber das Hinzufügen eines redundanten ISNULL() Wrappers tat es , im großen Maßstab.

+0

Können Sie die Lösung für wie zeigen in einem Beispiel sicherstellen/anzeigen, dass NULL nicht möglich ist, mit 'CONVERT()'? –

+1

Hallo O. R. - Entschuldigung, ich habe das eine Zeitlang nicht gesehen. Hier ist ein Beispiel. Wenn Sie CONVERT (BIT, U.REETRED), 0) AS Retired in Ihrer Ansicht haben, indem Sie ein Byte oder eine int-Spalte in ein Bit/Bool umwandeln, wird es nullbar. Sie können diese Spalte in Ihrer Sicht nicht nullfähig machen, indem Sie sie durch ISNULL (CONVERT (BIT, U.REETIRED), 0) AS Retired ersetzen. Wenn U. REETIRED nicht null war, um zu starten, ändert es funktionell nichts außer der Spalte in der Ansicht. WARNUNG: ISNULL() kann die Abfrageoptimierung und die Auswahl von Indizes beeinträchtigen. – user1664043

Verwandte Themen