2016-05-31 25 views
6

Esecuzione di MS SQL Server 2014 express. All'improvviso una delle colonne in una vista divenne nullable, nonostante fosse un'unione di due colonne non annullabili. Ti prego, aiutami a capire cosa sta succedendo qui:UNION di colonne non annullabili è annullabile

enter image description here

e l'Unione:

enter image description here

Che cosa mi manca?

Modifica con ulteriori informazioni: quando si esegue nuovamente la visualizzazione IncomingTransactions, la sua colonna ora diventa nulla, ma non dovrebbe essere! Ecco la definizione della colonna Quantità: (CASE PIN.StatusId WHEN 6 THEN PIN.QuantityReceived WHEN 7 THEN 0 ELSE PIN.QuantityRevised END) AS Quantity. Ciascuno dei campi quantità è non nullo e la dichiarazione caso è esaustiva. Il resto della query è un semplice join nel campo StatusId, che è un FK non Null, quindi sono ancora perso qui.

Edit 2: sulla base dei suggerimenti di YB sotto, ho creato un banco di prova minima che riproduce questo comportamento:

Create Table ybTest1 (Q1 decimal (7,2) not null, X int not null); 
GO 
Create View ybTestNSB As 
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1 
GO 

La colonna Q nella vista ybTest1 è nullo, anche se l'istruzione case è esaustivo . Anche se avvolgo lo 0 nel ramo ELSE con CAST(0 as decimal(7,2)), come suggerito da YB, è ancora nullo. O CASE non ha la semantica che ho pensato, o questo è un bug.

+1

La parte strana è Stato get 'not null', probabilmente dipende dal tipo di dati. Come hai creato la vista? Raccomando di lavorare con due tabelle di test, con tutti i tipi di dati come null e non null e vedere se è possibile riprodurre questo comportamento –

+1

Come stai usando la vista? Dove la clausola? Aggregati? A seconda della tua query, è possibile che tu abbia un record in una tabella che non esiste nella seconda tabella, risultando in un null utilizzato. Sotto il cofano un'UNIONE fa un ordinamento e si fonde per eliminare i duplicati. Se si desidera TUTTI i record, fare un UNIONE TUTTI Se non si cura dei duplicati, UNION ALL è molto più veloce. – JVC

+0

@JuanCarlosOropeza, sto indovinando Type, Id, PartTypeId e Status sono tutti campi chiave? Quantità, FiscalYearId, DataTransacted e Source non lo sono. – Clay

risposta

2

Quasi ogni colonna calcolata come risultato di un'espressione è considerata nullable in SQL Server. La soluzione alternativa è utilizzare ISNULL come si sta facendo. Questo è menzionato nel computed columns section qui

Il Motore di database determina automaticamente l'annullabilità di colonne calcolate sulla base delle espressioni utilizzate. Il risultato di maggior espressioni è considerato annullabile anche se solo colonne nonnullable sono presenti ... Un'espressione che è annullabile può essere trasformato in uno nonnullable specificando ISNULL(check_expression, constant), dove la costante è un valore non nullo sostituito per qualsiasi risultato nullo .

ma si applica ovunque sia derivata una colonna come risultato di un calcolo, incluso in una definizione di vista.

C'è poca o nessuna logica per analizzare se i null sono effettivamente possibili (a volte più difficile di quanto sembri dato che varie opzioni di set deprecate possono indurre errori nulli anziché di overflow così anche 1 + X potrebbe produrre un null nell'esempio) e sbaglia sul lato della cautela. Non vedo in alcun modo che l'espressione case possa emettere null in realtà, ma nella mia esperienza praticamente nessuna colonna calcolata verrà considerata nullable tranne quelle avvolte in isnull.

Quindi nel tuo caso di test è possibile sostituire

Create View ybTestNSB As 
Select (CASE X WHEN 0 THEN Q1 ELSE CAST(0 as decimal(7,2)) END) AS Q From ybTest1 

Con

Create View ybTestNSB As 
Select ISNULL(CASE X WHEN 0 THEN Q1 END, 0) AS Q From ybTest1 

Per evitare di dover mettere un fastidioso un'espressione del tutto ridondante lì.

+0

Questo sembra essere il caso Martin, ma non è [documentato come tale] (https://msdn.microsoft.com/en-us/library/ms181765.aspx?f=255&MSPPError=-2147217396). Citazione: "Se no input_expression = when_expression restituisce TRUE, il Motore di database di SQL Server restituisce else_result_expression se viene specificata una clausola ELSE o un valore NULL se non viene specificata alcuna clausola ELSE." Questo è lo stesso per le dichiarazioni dei casi semplici e cercate. La clausola ELSE non è chiaramente nulla nei miei esempi. – naasking

+0

@naasking yes, in realtà l'espressione 'case' non può restituire null.Ma c'è poca o nessuna logica per analizzare questo. Praticamente qualsiasi colonna calcolata sarà considerata nullable tranne quelle avvolte in isnull. –

+1

OK, strano che non abbia inferto NULL nel 2008 R2, ma lo sta facendo nel 2014. Abbiamo controllato due volte proprio ora, quindi sembra che MSSQL 2014 sia meno preciso del 2008. Questa risposta dovrà essere fatta, grazie. – naasking