Come si riscrivono le espressioni contenenti gli operatori standard IS DISTINCT FROM
e IS NOT DISTINCT FROM
in implementazioni SQL come Microsoft SQL Server 2008R2 che non le supportano?Come riscrivere IS DISTINCT FROM e NON DISTINTIVO DA?
risposta
La IS DISTINCT FROM
predicato è stato introdotto come caratteristica T151 di SQL: 1999, e la sua negazione leggibile, IS NOT DISTINCT FROM
, è stata aggiunta come caratteristica T152 di SQL: 2003. Lo scopo di questi predicati è garantire che il risultato del confronto di due valori sia True o False, mai Unknown.
Questi predicati funzionano con qualsiasi tipo comparabile (incluse righe, matrici e multiset) rendendo piuttosto complicato emularli esattamente. Tuttavia, SQL Server non supporta la maggior parte di questi tipi, in modo che possiamo ottenere abbastanza lontano controllando per argomenti nulli/operandi:
a IS DISTINCT FROM b
può essere riscritta come:((a <> b OR a IS NULL OR b IS NULL) AND NOT (a IS NULL AND b IS NULL))
a IS NOT DISTINCT FROM b
può essere riscritta come:(NOT (a <> b OR a IS NULL OR b IS NULL) OR (a IS NULL AND b IS NULL))
La propria risposta è errata in quanto non considera che FALSE OR NULL
restituisce sconosciuto. Ad esempio, NULL IS DISTINCT FROM NULL
deve essere valutato su False. Allo stesso modo, 1 IS NOT DISTINCT FROM NULL
deve essere valutato su False.In entrambi i casi, le tue espressioni producono Unknown.
Se l'implementazione SQL non implementa lo standard IS DISTINCT FROM
e IS NOT DISTINCT FROM
operatori SQL, è possibile riscrivere espressioni che li contengono utilizzando i seguenti equivalenze:
In generale:
a IS DISTINCT FROM b <==>
(
((a) IS NULL AND (b) IS NOT NULL)
OR
((a) IS NOT NULL AND (b) IS NULL)
OR
((a) <> (b))
)
a IS NOT DISTINCT FROM b <==>
(
((a) IS NULL AND (b) IS NULL)
OR
((a) = (b))
)
Questa risposta non è corretta quando viene utilizzato in un contesto in cui la differenza tra UNKNOWN e FALSE è importante. Penso che sia raro, però. Vedi la risposta accettata da @ChrisBandy.
Se un valore segnaposto può essere identificato che in realtà non si verifica nei dati, quindi COALESCE
è un'alternativa:
a IS DISTINCT FROM b <==> COALESCE(a, placeholder) <> COALESCE(b, placeholder)
a IS NOT DISTINCT FROM b <==> COALESCE(a, placeholder) = COALESCE(b, placeholder)
Questa è una risposta sbagliata però. Vedi l'ultimo paragrafo nella risposta di Chris. –
Sì, questa risposta non è corretta se utilizzata in un contesto in cui è importante la differenza tra UNKNOWN e FALSE. Penso che sia raro, però. –
@JasonKresowaty: Questo non è affatto raro. In qualsiasi predicato come '(a IS DISTINCT FROM b) AND something', la distinzione tra' UNKNOWN' e 'FALSE' è essenziale. Se 'a' e' b' sono entrambi 'NULL', la tua emulazione genererà' NULL', indipendentemente dal fatto che 'something' sia' TRUE' o 'FALSE'. –
Un avvertimento in riscrittura è distinto da e non è distinto dal sarebbe per non interferire con l'utilizzo di indici, almeno quando si utilizza SQL Server. In altre parole, quando si utilizza il seguente:
WHERE COALESCE(@input, x) = COALESCE(column, x)
SQL Server non sarà in grado di utilizzare qualsiasi indice che include colonna. Quindi, in una clausola WHERE, sarebbe preferibile utilizzare il modulo
WHERE @input = column OR (@input IS NULL AND column IS NULL)
di approfittare di tutti gli indici per colonna. (Parens utilizzato solo per chiarezza)
+1 per menzionare per come le funzioni uccidono l'uso dell'indice. È come sono finito qui in primo luogo. – Serge
Un'altra soluzione che mi piace sfrutta il vero valore booleano a due valori di EXISTS combinato con INTERSECT. Questa soluzione dovrebbe funzionare in SQL Server 2005+.
a IS NOT DISTINCT FROM b
può essere scritta come:EXISTS(SELECT a INTERSECT SELECT b)
Come documentato, INTERSECT considera due valori NULL uguali, quindi se entrambi sono NULL, quindi intersecano risultati in un'unica fila, così ESISTE si rivela vera.
a IS DISTINCT FROM b
può essere scritta come:NOT EXISTS(SELECT a INTERSECT SELECT b)
Questo approccio rappresenta molto più conciso, se si dispone di più colonne nullable è necessario confrontare in due tabelle. Ad esempio, per restituire righe in TableB che hanno valori diversi per Col1, Col2, o Col3 rispetto TableA, quanto segue può essere utilizzato:
SELECT *
FROM TableA A
INNER JOIN TableB B ON A.PK = B.PK
WHERE NOT EXISTS(
SELECT A.Col1, A.Col2, A.Col3
INTERSECT
SELECT B.Col1, B.Col2, B.Col3);
Paul White spiega questa soluzione in modo più dettagliato: http://sqlblog.com/blogs/paul_white/archive/2011/06/22/undocumented-query-plans-equality-comparisons.aspx
Questo dovrebbe essere accettato rispondi, poiché riscrive il predicato in un modo che non duplica i riferimenti a 'a' e' b'. Per espressioni non deterministiche 'a' e' b', o espressioni con effetti collaterali (come la registrazione), sarebbe molto utile. Il tuo secondo esempio emula anche '(A.Col1, A.Col2, A.Col3) IS DISTINCT FROM (B.Col1, B.Col2, B.Col3)', che è supportato solo in modo nativo da PostgreSQL (a mia conoscenza). Un predicato molto utile, a volte. –
Ottima risposta, preferisco quella accettata – Jocie
Per il riferimento, l'implementazione più canonica (e leggibile) di IS [ NOT ] DISTINCT FROM
sarebbe un'espressione ben formattata CASE
. Per IS DISTINCT FROM
:
CASE WHEN [a] IS NULL AND [b] IS NULL THEN FALSE
WHEN [a] IS NULL AND [b] IS NOT NULL THEN TRUE
WHEN [a] IS NOT NULL AND [b] IS NULL THEN TRUE
WHEN [a] = [b] THEN FALSE
ELSE TRUE
END
Ovviamente, altre soluzioni (specificamente John Keller's, utilizzando INTERSECT
) sono più concisi.
Queste espressioni possono essere un buon sostituto per la è distinto dalla logica e prestazioni migliori rispetto ai precedenti esempi perché finiscono per essere compilata per server SQL in una singola espressione predicato che si tradurrà in circa. metà dell'operatore costa su un'espressione di filtro. Sono essenzialmente le stesse delle soluzioni fornite da Chris Bandy, tuttavia usano le funzioni nidificate ISNULL e NULLIF per eseguire i confronti sottostanti.
(...ovviamente ISNULL potrebbe essere sostituito con COALESCE, se si preferisce)
a IS DISTINCT FROM b
può essere riscritta come:ISNULL(NULLIF(a, b), NULLIF(b, a)) IS NOT NULL
a IS NOT DISTINCT FROM b
può essere riscritta come:ISNULL(NULLIF(a, b), NULLIF(b, a)) IS NULL
a IS NOT DISTINCT FROM b
può essere riscritta come:
(a IS NOT NULL AND b IS NOT NULL AND a=b) OR (a IS NULL AND b is NULL)
a IS DISTINCT FROM b
può essere riscritta come:
NOT (a IS NOT DISTINCT FROM b)
- 1. SQL Server supporta la clausola FROM DISTINCT FROM?
- 2. Perché "SELECT DISTINCT a, b FROM ..." restituisce meno record di "SELECT DISTINCT A + '|' + B DA ... "?
- 3. Distintivo di notifica push distintivo incremento
- 4. DISTINCT() e OrderBy problema
- 5. Come riscrivere _.every/_. Tutto da Underscore.js utilizzando _.reduce (e _.each)
- 6. UISegmentedControl con numero distintivo
- 7. SELECT DISTINCT e contare
- 8. SELECT COUNT (DISTINCT [name]) da diverse tabelle
- 9. iOS, diminuzione icona distintivo numero
- 10. DISTINCT clausola con WHERE
- 11. input is URL, come proteggerlo da xss
- 12. SQL Query - Combina DISTINCT e TOP?
- 13. LINQ: Seleziona da IEnumerable con Distinct/GroupBy e ordinamento - possibile?
- 14. Come riscrivere stesso file
- 15. Usando DISTINCT e TOP allo stesso tempo
- 16. PostgreSQL - "ON DISTINCT" e "GROUP BY" sintassi
- 17. select count (*) from select
- 18. Come posso riscrivere/reindirizzare da http a https in Go?
- 19. Yii Advanced URL riscrivere
- 20. aggiornamento del contatore distintivo a Swift
- 21. ON DISTINCT in Django
- 22. SELECT DISTINCT e ORDER BY in MySQL
- 23. DISTINCT clausola in SQLite
- 24. Impostare il numero distintivo applicazione iOS 9
- 25. come ignorare `operatore is`
- 26. Python: Differenza tra `is` e` == `?
- 27. Come si fa a DISTINCT e ORDER BY in PostgreSQL?
- 28. Contando DISTINCT su più colonne
- 29. Riscrivere ospite nginx e ProxyPass di calamari
- 30. Utilizzo di DISTINCT in JPA
((a <> b O a IS NULL O b IS NULL) E NON (a IS NULL E b IS NULL)): non possiamo solo <> b o a è nullo xor b è nullo –