제로 행이 일치하더라도 SELECT가 상수 값을 리턴하도록 함


15

이 select 문을 고려하십시오.

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

플레이어의 다른 열과 query_id함께 값이 있는 열 을 반환합니다 1.

select가 일치하는 행을 찾지 못하더라도 위의 SQL이 적어도 query_idof 1를 반환하도록하려면 어떻게해야합니까?

BTW, PostgreSQL 8.4입니다.

답변:


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

또는 대안으로 ( 두 번째 하위 선택이 필요하지 않아 더 빠를 있음) :

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

위의 내용을보다 "작은"표현으로 다시 작성할 수 있습니다.

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

그러나 나는 명백한 CTE ( with...)가 더 읽기 쉽다고 생각하지만 (항상 보는 사람의 눈에 있음).


1
첫 번째 예를 시도 할 때 ALL 키워드가 필요하지 않은 것 같습니다.
Nathanael Weiss

2
@NatWeiss : 당신이 특정 순서를 필요로하는 경우, 당신은 을 공급 order by. 두 번째 테이블은 정확히 하나의 행과 하나의 열로 가상 테이블을 "만들고"외부 조인 ( "실제"조인 조건없이)을 수행하므로 항상 하나 이상의 행을 다시 가져옵니다. select *프로덕션 코드에서 사용 하는 것은 좋지 않습니다. 하지마 항상 필요한 열을 나열하십시오. 임시 쿼리 에서만select * 사용해야 합니다.
a_horse_with_no_name

2
@NatWeiss : "기타 조인"에 대한 "대체 구문"이란 무엇입니까? 왜 left join읽을 수 없다고 생각 합니까?
a_horse_with_no_name 5

2
@NatWeiss : where 절의 암시 적 조인은 잘못된 코딩 스타일이므로 피해야합니다. 그것은 당신에게 오류를주지 않고 원치 않는 데카르트 조인으로 이어질 수 있습니다. 또한 결합 및 필터링이라는 두 가지 관계형 개념을 명확하게 구분합니다.
a_horse_with_no_name

4
re : "union"절의 "all"수정 자 필요하지 않음 : 쿼리 플래너에게 ed 쿼리 에서 중복 행이 나오지 않을 것으로 예상하거나 명시 적으로 알리는 경우 UNION ALL보다 효율적일 UNION수 있습니다. UNION그것들이 출력되기를 원합니다. ALL수정자를 사용 하지 않으면 DISTINCT키워드 와 같은 방식으로 중복 행을 제거하고 (각 반환 된 항목 중 하나만) 중복 된 결과를 원한다고 가정 하고 추가 시간에 결과를 다시 작성해야합니다. 따라서 출력 행 중복 제거가 특별히 필요한 경우 ALLUNION아니면 함께 사용하십시오 .
David Spillett

7

하나 또는 0 개의 행만 다시 기대하면 다음과 같이 작동합니다.

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

행이 없으면 query_id를 제외한 모든 값이 null 인 행 하나를 반환합니다.


2
좋은 트릭. 유일한 단점은 COL1과 COL2의 값 수도 없다 속하는 조건과 일치하는 하나 이상의가 동일한 행에, 만약username = 'foobar'
a_horse_with_no_name

1
coalesce ()도 이런 방식으로 사용될 수 있습니까?
Nathanael Weiss

1
Coalesce는 테이블에서 아무것도 계획되지 않은 행을 생성하지 않습니다.
David Aldridge

1
@a_horse_with_no_name yes. 테이블 및 열 이름은 술어가 테이블의 후보 키에 있다고 제안하므로 0 개 또는 1 개의 행이 투사됩니다.
David Aldridge

3

여기 늦게 Chiming하지만 작동하는 구문이 있습니다 (적어도 9.2에서는 이전 버전을 시도하지 않았습니다).

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;

"a"의 전체 내용이 null 인 경우 "공백"행만 반환합니다.

즐겨. / 비트 헤드


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.