Mentre interrogavo il server di produzione per risolvere un problema critico, improvvisamente una query attirò completamente la mia attenzione. Abbiamo scritto una query che è stata creata per trovare i record che esistono nella tabella A ma non esistono nella tabella B, basato su una determinata colonna. La query era sintatticamente corretta e funzionava senza errori, ma non restituiva alcun risultato. C'erano alcuni record che speravamo di ottenere nei risultati, quindi abbiamo studiato il motivo per cui la query corretta non ne restituiva alcuna.
Il NON IN la clausola restituisce le righe dalla tabella esterna che non esistono nella tabella interna utilizzata nella sottoquery. In questo tutorial, esamineremo l'utilizzo della clausola NOT IN con valori null.
Esempio della clausola NOT IN
SELECT * FROM OuterTable WHERE PK_Id NOT IN (SELEZIONA FK_id da InnerTable);
Esempio della clausola NOT IN con valori NULL in InnerTable.
CREA PRODOTTO TABELLA (PK_Product_Id INT PRIMARY KEY, Name VARCHAR (255)); INSERISCI NEI VALORI DEL PRODOTTO (1, 'Coca Cola'), (2, 'Pepsi'), (3, 'Mango'), (4, '7 Su'); CREATE TABLE PRODUCT_DETAILS (PK_Details_Id INT PRIMARY KEY, [Descrizione] VARCHAR (500), FK_Product_Id INT PRODOTTO DI RIFERIMENTI KEY STRANIERI (PK_Product_Id)); INSERISCI NEI VALORI DATI DEL PRODOTTO (100, "500 ML è buono", 1); INSERISCI NEI VALORI DATI DEL PRODOTTO (101, "500 ML è buono", 2); INSERISCI NEI VALORI DATI DEL PRODOTTO (102, "500 ML è buono", 3); INSERISCI NEI VALORI DATI DEL PRODOTTO (103, "500 ML è buono", NULL);
Come mostrato nell'immagine sopra, la tabella PRODUCT_DETAILS ne contiene una Valore NULL.
Ora, il nostro obiettivo è per trovare i nomi dei prodotti dalla tabella Prodotto i cui dettagli non sono disponibili nella tabella Product_Details. Idealmente, dovrebbe restituire il Prodotto 4 dalla tabella Prodotto poiché i dettagli del Prodotto 4 non esistono nella tabella Product_Details.
Potremmo pensare che questo possa essere ottenuto facilmente usando il predicato NOT IN scrivendo la seguente query.
SELECT * FROM PRODUCT WHERE PK_Product_Id NOT IN (SELEZIONA Fk_Product_Id FROM PRODUCT_DETAILS);
La query sopra non restituisce nulla anche se sintatticamente è corretto. A causa dell'esistenza di un valore NULL nella tabella Product_Details, non riesce a restituire i risultati previsti.
SQL Server utilizza il Logica a tre valori concetto qui.
Come sappiamo, esiste un valore NULL nella tabella Product_Details nella colonna fk_product_id. UN Il valore NULL è un valore sconosciuto o mancante.
SQL Server converte la clausola NOT IN utilizzando la logica a tre valori e la valuta nel modo seguente.
NON IN (SELEZIONA 1 O 2 O 3 O NULL) NON IN (Fk_product_id = 1 OR Fk_product_id = 2 OR Fk_product_id = 3 O Fk_product_id = NULL) NON IN (Fk_product_id = 1 O Fk_product_id = 2 O Fk_product_id = 3 O SCONOSCIUTO) NON IN (VERO O VERO O VERO O SCONOSCIUTO) NON IN (VERO O VERO O SCONOSCIUTO) NON IN (VERO O SCONOSCIUTO) NON IN (SCONOSCIUTO)
Come il il risultato finale viene valutato come UNKNOWN, la query NOT IN non restituisce alcun risultato a causa dell'esistenza di un valore NULL.
La soluzione consiste nel far funzionare le query NOT IN con l'esistenza di valori NULL e utilizzare la logica a due valori, solo VERO o FALSO.
- NON CONTO NON È NULL Filtro SELEZIONA * DA PRODOTTO DOVE PK_Product_Id NON IN (SELEZIONA Fk_Product_Id FROM PRODUCT_DETAILS WHERE Fk_Product_Id NON È NULL); --NOT Exists SELECT * FROM PRODUCT Prd WHERE NOT EXISTS (SELEZIONA Fk_Product_Id FROM PRODUCT_DETAILS WHERE Fk_Product_Id = Prd.PK_Product_Id);
NOT EXISTS ci dà anche i risultati giusti perché utilizza la logica booleana a due valori, solo TRUE o False, per filtrare le righe.
--Utilizzo Sinistra Join SELECT * FROM PRODUCT Prd LEFT ENTRA PRODUCT_DETAILS PrdDetails ON Prd. PK_Product_Id = PrdDetails .FK_Product_Id WHERE PrdDetails. FK_Product_Id È NULL
Usando il join sinistro, possiamo anche recuperare i record che esistono nella tabella Product ma non esistono nella pagina Product_Details quando eseguiamo un join basato sulla chiave primaria (pk_product_id) e sulla chiave esterna (fk_product_id).