Получение SELECT для возврата постоянного значения, даже если нулевые строки совпадают


15

Рассмотрим это утверждение выбора:

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

Возвращает столбец query_idсо значением 1вместе с другими столбцами игрока.

Как можно заставить приведенный выше SQL возвращать хотя бы значение query_idof, 1даже если select не находит подходящих строк?

Кстати, это 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 не нужно?
Натанаэль Вайс

2
@NatWeiss: если вам нужен конкретный заказ, вы должны предоставить order by. Второй «создает» виртуальную таблицу с ровно одной строкой и одним столбцом и выполняет внешнее соединение (без каких-либо «реальных» условий соединения), таким образом, вы всегда возвращаете хотя бы одну строку. Использование select *в рабочем коде - плохой стиль. Не делай этого. Всегда перечисляйте нужные вам столбцы. select *следует использовать только в специальных запросах.
a_horse_with_no_name

2
@NatWeiss: какой «альтернативный синтаксис» для «других объединений» вы имеете в виду. А почему ты считаешь left joinне читабельным?
a_horse_with_no_name

2
@NatWeiss: неявное соединение в предложении where является плохим стилем кодирования, и его следует избегать. Это может привести к нежелательному объединению декартов, не давая вам ошибки. И он четко разделяет две (реляционные) концепции объединения и фильтрации
a_horse_with_no_name

4
re: модификатор «all» предложения «union» не требуется: UNION ALLиногда он может быть более эффективным, чем UNION, поскольку вы явно указываете планировщику запросов, что вы ожидаете, что в UNIONзапросах ed не будет повторяющихся строк, или если Вы хотите, чтобы они были выведены. Без ALLмодификатора он предполагает, что вы хотите удалить дубликаты строк (только одну возвращаемую), так же, как с DISTINCTключевым словом, и гарантировать, что может потребоваться дополнительная проверка или повторное сканирование результатов. Так что используйте ALLс, UNIONесли вам не требуется дедупликация выходных строк.
Дэвид Спиллетт

7

Если вы ожидаете только одну или ноль строк назад, то это также будет работать:

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

Это вернет одну строку со всеми значениями, имеющими нулевое значение, кроме query_id, если строка не найдена.


2
Хороший трюк. Единственным недостатком является то, что значения для col1 и col2 могут не принадлежать одной и той же строке, если существует более одного условия, соответствующегоusername = 'foobar'
a_horse_with_no_name

1
Может ли coalesce () также использоваться таким образом?
Натанаэль Вайс

1
Coalesce не будет генерировать строку, где ни одна не будет спроецирована из таблицы.
Дэвид Олдридж

1
@a_horse_with_no_name да, хотя имена таблиц и столбцов предполагают, что предикат находится на ключе-кандидате для таблицы, поэтому будет спроецирован ноль или одна строка.
Дэвид Олдридж

3

Здесь перезвонили немного позже, но вот синтаксис, который работает (по крайней мере в 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» равно нулю.

Наслаждаться. / bithead


-1
select isnull(column,1) from table

2
Это не создаст дополнительную строку, когда запрос возвращает 0 строк.
ypercubeᵀᴹ
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.