2013-04-24 13 views
5

Qual è il modo migliore per farlo in una query in mysql?Un'altra clausola WHERE se non ci sono risultati

SELECT * FROM products WHERE language = 1 

se non v'è alcun risultato

SELECT * FROM products WHERE language = 2 AND country = 1 

se non v'è alcun risultato

SELECT * FROM products WHERE language = 2 AND country = 2 
+0

Quali colonne sono '' *? – Kermit

+0

Sfortunatamente questa non è una query in MySQL: cosa ti aspetti di ottenere da questo – gbn

+0

Penso che tu possa ottenere il risultato "logico" desiderato con ORDER – lvil

risposta

7

L'ho modificato per farlo funzionare, ma non è più elegante.


L'originale (senza l'ultimo e non esiste) aveva un difetto.

Risulta che non è così intelligente come pensavo. Vedi i commenti qui sotto. Fallisce se la prima e la terza query restituiscono dati. Funziona se hai solo un sindacato, ma non due o più.


E 'abbastanza facile in mysql:

select SQL_CALC_FOUND_ROWS * from products where language = 1 
union 
SELECT * FROM products WHERE language = 2 AND country = 1 and found_rows()=0 
union 
SELECT * FROM products WHERE language = 2 AND country = 2 and found_rows()=0 
AND not exists(select * from products where language = 1) 

Vedi la discussione di found_rows() e SQL_CALC_FOUND_ROWS qui: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_found-rows

+1

Puoi contare su found_rows in una istruzione UNION? – gbn

+0

+1 per l'idea! :) – biziclop

+0

@gbn È possibile se non stai usando LIMIT ovunque e verificando lo 0. –

1

MySQL manca caratteristiche per lo consentano, in un colpo solo
Esempi: DENSE_RANK funzione finestra, o TOP..WITH TIES

Quindi, senza utilizzare una tabella temporanea o istruzioni IF (che richiedono comunque una procedura memorizzata in MySQL), quindi filtrare ciò sul client al valore di priorità più basso. Cioè, consumano le righe fino a quando il valore cambia

SELECT *, 1 AS priority FROM products WHERE language = 1 
UNION ALL 
SELECT *, 2 AS priority FROM products WHERE language = 2 AND country = 1 
UNION ALL 
SELECT *, 3 AS priority FROM products WHERE language = 2 AND country = 2 
ORDER BY priority; 

Questo non rimuovere andata e ritorno al server MySQL, anche se non è l'ideale. Ed evita anche di rivalutare i SELECT precedenti nelle clausole EXISTS

+0

È possibile eseguire questa operazione in una singola selezione se si è valutata la priorità come condizione del caso - qualcosa come 'case language when 1 then 1 quando 2 poi lingua + nazione altro 4 fine'. –

2

si potrebbe usare qualcosa di simile a quanto segue: (a cura di uso EXISTS e LIMIT in base ai commenti).

(
SELECT * FROM products WHERE language = 1 
) 
UNION 
(
SELECT * FROM products WHERE language = 2 AND country = 1 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1) 
) 
UNION 
(
SELECT * FROM products WHERE language = 2 AND country = 2 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 2 AND country = 1 limit 1) 
AND NOT EXISTS(SELECT count(*) FROM products WHERE language = 1 limit 1) 
) 

È possibile verificare con query annidate e contare (*) che le query precedenti erano NULL.

+2

L'utilizzo di non esiste potrebbe essere migliore del controllo di un conteggio 0. –

+0

@ShawnBalestracci sarà eseguito nuovamente su tutte le sottoquery (COUNT o EXISTS - non importa)? Forse lasciare unire + check per null sarebbe un approccio migliore? –

+0

Ho la sensazione che l'ottimizzatore calcoli il ramo ottimale e precalcoli quelli solo una volta. Ecco perché i motori SQL fanno :). –

1

Prova:

select p.* 
from (select min(language) minlang, min(country) minctry 
     from products where language = 1 or 
          (language = 2 and country in (1,2))) c 
join products p 
on p.language = c.minlang and (c.minlang=1 or p.country=c.minctry) 
1

Sembra non c'è buon modo e, se possibile, è meglio farne una procedura, sia compilando la tabella temporanea o restituendo l'oggetto RowSet al cliente

Come mai se non ciò che è possibile ti sembra di avere le query limite secondari e terziari:

SELECT * FROM products WHERE language = 1 

UNION ALL 

SELECT * FROM products WHERE language = 2 AND country = 1 
    AND NOT EXISTS (SELECT * FROM products WHERE language = 1) 

UNION ALL 

SELECT * FROM products WHERE language = 2 AND country = 2 
    AND NOT EXISTS (SELECT * FROM products WHERE language = 1 OR (language = 2 AND country = 1)) 

Ma che proprio deve essere brutto e lento.

Forse LEFT JOIN con IS NULL sarebbe meglio che non ESISTE se