Conseguir que o SELECT retorne um valor constante, mesmo que zero linha corresponda

15

Considere esta instrução select:

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

Retorna a coluna query_idcom valor 1junto com as outras colunas de um jogador.

Como se poderia fazer o retorno SQL acima, pelo menos, o query_idde 1mesmo se as descobertas selecione há linhas que jogo?

BTW, é o PostgreSQL 8.4.

Nathanael Weiss
fonte

Respostas:

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');

Ou como alternativa ( pode ser mais rápido, pois não é necessária nenhuma segunda subseleção):

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

Você pode reescrever o acima para uma representação mais "compacta":

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

Mas acho que o CTE explícito ( with...) é mais legível (embora isso esteja sempre aos olhos de quem vê).

um cavalo sem nome
fonte
1
Ao experimentar o primeiro exemplo, parece que a palavra-chave ALL não é necessária?
Nathanael Weiss
2
@ NatWeiss: se você precisar de um pedido específico, precisará fornecer um order by. O segundo "cria" uma tabela virtual com exatamente uma linha e uma coluna e faz uma junção externa (sem nenhuma condição de junção "real"), portanto, você sempre recupera pelo menos essa linha. Usar select *código de produção é um estilo ruim. Não faça isso. Sempre liste as colunas necessárias. select *deve ser usado apenas em consultas ad-hoc.
precisa saber é o seguinte
2
@ NatWeiss: a que "sintaxe alternativa" para "outras junções" você está se referindo. E por que você acha que left joinnão é legível?
precisa saber é o seguinte
2
@ NatWeiss: a junção implícita na cláusula where é ruim no estilo de codificação e deve ser evitada. Isso pode levar a junções cartesianas indesejadas sem causar erros. E separa claramente os dois conceitos (relacionais) de aderir e filtrando
a_horse_with_no_name
4
re: o modificador "all" da cláusula "union" não é necessário: UNION ALLàs vezes pode ser mais eficiente do que UNIONquando você diz explicitamente ao planejador de consultas que você espera que não haja linhas duplicadas saindo das UNIONconsultas ed ou se você quer que eles sejam produzidos? Sem o ALLmodificador, ele pressupõe que você deseja remover linhas duplicadas (apenas uma de cada uma retornada) da mesma forma que a DISTINCTpalavra - chave e para garantir que seja necessário recorrer + verificar novamente os resultados por mais tempo. Portanto, use ALLcom UNIONmenos que você precise especificamente da deduplicação da linha de saída.
21413 David Spillett
7

Se você espera apenas uma ou zero linhas de volta, isso também funcionaria:

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

Isso retornará uma linha com todos os valores com nulo, exceto query_id se nenhuma linha for encontrada.

David Aldridge
fonte
2
Bom truque. O único inconveniente é que os valores de col1 e col2 possam não pertencer à mesma linha, se houver mais de uma correspondência a condiçãousername = 'foobar'
a_horse_with_no_name
1
Coalesce () também poderia ser usado dessa maneira?
Nathanael Weiss
1
A coalescência não geraria uma linha na qual nenhuma é projetada da tabela.
David Aldridge
1
@a_horse_with_no_name yes, embora os nomes de tabela e coluna sugiram que o predicado esteja em uma chave candidata para a tabela, então zero ou uma linha seria projetada.
David Aldridge
3

Chiming atrasado aqui, mas aqui está uma sintaxe que funciona (pelo menos na 9.2, ainda não tentei versões anteriores).

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;

Retornará apenas a linha "em branco" se todo o conteúdo de "a" for nulo.

Desfrutar. / bithead

Kirk Roybal
fonte
-1
select isnull(column,1) from table
user86795
fonte
2
Isso não produzirá uma linha extra quando a consulta retornar 0 linhas.
ypercubeᵀᴹ