Ottenere SELECT per restituire un valore costante anche se zero righe corrispondono


15

Considera questa dichiarazione selezionata:

SELECT *, 
       1 AS query_id 
FROM players 
WHERE username='foobar';

Restituisce la colonna query_idcon valore 1insieme alle altre colonne di un giocatore.

Come si potrebbe rendere il ritorno di SQL sopra almeno query_iddi 1anche se la selezione non trova righe che corrispondono?

A proposito, è PostgreSQL 8.4.

Risposte:


22
SELECT col1, 
       col2, 
       col3, 
       1 AS query_id 
FROM players 
WHERE username='foobar'
union all 
select null,
       null,
       null,
       1
where not exists (select 1 from players where username = 'foobar');

O in alternativa ( potrebbe essere più veloce in quanto non è richiesta una seconda sottoselezione):

with qid (query_id) as (
   values (1)
) 
select p.*, 
       qid.query_id
from qid 
  left join players as p on (p.useranme = 'foobar');

Puoi riscrivere quanto sopra in una rappresentazione più "compatta":

select p.*, 
       qid.query_id
from (values (1)) as qid (query_id)
  left join players as p on (p.useranme = 'foobar');

Ma penso che il CTE esplicito ( with...) sia più leggibile (sebbene ciò sia sempre agli occhi di chi guarda).


1
Nel provare il primo esempio, sembra che la parola chiave ALL non sia necessaria?
Nathanael Weiss,

2
@NatWeiss: se avete bisogno di un ordine specifico, si devono fornire un order by. Il secondo "crea" una tabella virtuale con esattamente una riga e una colonna e fa un join esterno (senza alcuna condizione di join "reale"), quindi si ottiene sempre almeno quella riga. L'uso select *nel codice di produzione è un cattivo stile. Non farlo Elenca sempre le colonne necessarie. select *dovrebbe essere utilizzato solo nelle query ad hoc.
a_horse_with_no_name

2
@NatWeiss: a quale "sintassi alternativa" per "altri join" ti riferisci. E perché pensi che left joinnon sia leggibile?
a_horse_with_no_name

2
@NatWeiss: il join implicito nella clausola where è un cattivo stile di codifica e dovrebbe essere evitato. Può portare a unioni cartesiane indesiderate senza darti un errore. E separa chiaramente i due concetti (relazionali) di unione e filtro
a_horse_with_no_name

4
ri: il modificatore "tutto" della clausola "unione" non è necessario: a UNION ALLvolte può essere più efficiente di UNION, poiché stai dicendo esplicitamente al pianificatore di query che o ti aspetti che non ci siano righe duplicate che escono dalle UNIONquery ed o ci vuoi che vengano emessi. Senza il ALLmodificatore si presuppone che si desideri rimuovere le righe duplicate (solo una per ciascuna restituita) proprio come con la DISTINCTparola chiave, e per garantire che potrebbe essere necessario ricorrere + ripetere la scansione dei risultati un tempo extra. Quindi utilizzare ALLcon a UNIONmeno che non sia specificamente necessario la deduplicazione della riga di output.
David Spillett,

7

Se ti aspetti solo una o zero righe, funzionerebbe anche:

SELECT
  max(col1) col1,
  max(col2) col2, 
  1 AS query_id 
FROM
  players 
WHERE
  username='foobar';

Ciò restituirà una riga con tutti i valori che hanno null tranne query_id se non viene trovata alcuna riga.


2
Bel trucco. L'unico inconveniente è che i valori di col1 e col2 potrebbero non appartenere alla stessa riga, se ce n'è più di uno corrispondente alla condizioneusername = 'foobar'
a_horse_with_no_name

1
Coalesce () potrebbe essere utilizzato anche in questo modo?
Nathanael Weiss,

1
Coalesce non genererebbe una riga in cui nessuno è proiettato dalla tabella.
David Aldridge,

1
@a_horse_with_no_name yes, anche se i nomi di tabella e colonna suggeriscono che il predicato si trova su una chiave candidata per la tabella, in modo da proiettare zero o una riga.
David Aldridge,

3

Ritornando in ritardo qui, ma ecco una sintassi che funziona (almeno in 9.2, non ho provato le versioni precedenti).

SELECT (COALESCE(a.*,b.*::players)).*
FROM ( SELECT col1,  col2,  col3, 1 AS query_id 
       FROM players WHERE username='foobar' ) a
RIGHT JOIN (select null col1, null col2, null col3, 1 col4) b
ON a.query_id = b.col4;

Restituirà la riga "vuota" se l'intero contenuto di "a" è nullo.

Godere. / bithead


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.