Come rendere una colonna della vista NOT NULL


85

Sto cercando di creare una vista in cui voglio che una colonna sia solo vera o falsa. Tuttavia, sembra che non importa quello che faccio, SQL Server (2008) crede che la mia colonna di bit possa in qualche modo essere nulla.

Ho una tabella chiamata "Prodotto" con la colonna "Stato" che è INT, NULL. In una vista, voglio restituire una riga per ogni riga in Product, con una colonna BIT impostata su true se la colonna Product.Status è uguale a 3, altrimenti il ​​campo bit dovrebbe essere falso.

SQL di esempio

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

Se salvo questa query come vista e guardo le colonne in Esplora oggetti, la colonna HasStatus è impostata su BIT, NULL. Ma non dovrebbe mai essere NULL. C'è qualche trucco SQL magico che posso usare per forzare questa colonna NOT NULL.

Si noti che, se rimuovo CAST()intorno a CASE, la colonna è impostata correttamente come NOT NULL, ma poi il tipo di colonna è impostato su INT, che non è quello che voglio. Voglio che sia BIT. :-)

Risposte:


152

Puoi ottenere ciò che desideri riorganizzando un po 'la query. Il trucco è che ISNULLdeve essere all'esterno prima che SQL Server capisca che il valore risultante non potrà mai essere NULL.

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

Uno dei motivi per cui in realtà lo trovo utile è quando si utilizza un ORM e non si desidera che il valore risultante venga mappato a un tipo nullable. Può rendere le cose più facili se la tua applicazione vede il valore come se non fosse mai nullo. Quindi non è necessario scrivere codice per gestire eccezioni null, ecc.


@ Gunder: non preoccuparti, in realtà è un po 'arcano. Ciò è utile anche quando si crea una colonna di bit calcolati in una tabella e si desidera che il risultato non sia annullabile.
D'Arcy Rittich

8
Avevo bisogno di qualcosa di simile, e ho scoperto che COALESCE()non ha funzionato, in realtà si deve usareISNULL()
EvilBob22

@ EvilBob22 È strano, perché sia ​​COALESCE che ISNULL possono restituire NULL. Immagino che sia solo una stranezza del compilatore.
D'Arcy Rittich

1
Questo, per un miliardo, per far sì che EntityFramework deduca una chiave quando normalmente non verrebbe dedotta.
Erik


3

Cordiali saluti, per le persone che si imbattono in questo messaggio, l'aggiunta di ISNULL () all'esterno del cast / convert può rovinare l'ottimizzatore sulla tua vista.

Avevamo 2 tabelle che utilizzavano lo stesso valore di una chiave di indice ma con tipi di precisione numerica diversa (pessima, lo so) e il nostro punto di vista era unirsi a loro per produrre il risultato finale. Ma il nostro codice middleware stava cercando un tipo di dati specifico e la vista aveva restituito un CONVERT () intorno alla colonna

Ho notato, come ha fatto l'OP, che i descrittori di colonna del risultato della vista lo definivano come nullable e stavo pensando che fosse una chiave primaria / esterna su 2 tabelle; perché dovremmo volere che il risultato sia definito come nullable?

Ho trovato questo post, ho lanciato ISNULL () intorno alla colonna e voilà - non annullabile più.

Il problema era che le prestazioni della vista andavano dritte nel water quando una query filtrava su quella colonna.

Per qualche motivo, un CONVERT () esplicito nella colonna dei risultati della vista non ha rovinato l'ottimizzatore (avrebbe dovuto farlo comunque a causa delle diverse precisioni) ma l'aggiunta di un wrapper ISNULL () ridondante lo ha fatto, in un grande modo.


Potresti mostrare la soluzione su come garantire / indicare la non annullabilità con CONVERT()in un esempio, per favore?
OR Mapper

1
Ciao OPPURE - mi spiace di non averlo visto per un po '. Ecco un esempio. Se hai CONVERT (BIT, U.RETIRED), 0) AS Ritirato nella tua vista, trasformando diciamo un byte o una colonna int in un bit / bool, allora diventa nullable. Puoi rendere quella colonna nella tua vista non annullabile sostituendola con ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Ritirato. Se U.RETIRED non era nullo per iniziare, funzionalmente non cambia nulla tranne la colonna nella vista. ATTENZIONE: ISNULL () può interferire con l'ottimizzazione della query e la scelta degli indici.
user1664043

-3

Tutto quello che puoi fare in un'istruzione Select è controllare i dati che il motore di database ti invia come client. L'istruzione select non ha alcun effetto sulla struttura della tabella sottostante. Per modificare la struttura della tabella è necessario eseguire un'istruzione Alter Table.

  1. Innanzitutto assicurati che al momento non ci siano valori nulli in quel campo di bit nella tabella
  2. Quindi eseguire la seguente istruzione ddl: Alter Table dbo.Product Alter column status bit not null

Se, otoh, tutto ciò che stai cercando di fare è controllare l'output della vista, allora quello che stai facendo è sufficiente. La tua sintassi garantirà che l'output della colonna HasStatus nel set di risultati delle viste non sarà mai effettivamente sarà nullo. Sarà sempre valore bit = 1 o valore bit = 0. Non preoccuparti di ciò che dice l'esploratore oggetti ...


6
Non voglio cambiare la colonna della tabella. La colonna è definita come una colonna intera, che consente null. Questo si adatta alle nostre specifiche. Ma ho bisogno di una vista che restituisca una colonna con un campo di bit, che non può essere nullo. Non è sufficiente che io sappia che non può essere null, la colonna deve essere NOT NULL, in modo che venga mappata correttamente nel nostro ORM.
René
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.