考虑以下选择语句:
SELECT *,
1 AS query_id
FROM players
WHERE username='foobar';
它返回query_id
带有值的列1
以及玩家的其他列。
如何将一个至少让上面的SQL回报query_id
的1
,即使选择,反而找不到行那场比赛?
顺便说一句,它是PostgreSQL 8.4。
考虑以下选择语句:
SELECT *,
1 AS query_id
FROM players
WHERE username='foobar';
它返回query_id
带有值的列1
以及玩家的其他列。
如何将一个至少让上面的SQL回报query_id
的1
,即使选择,反而找不到行那场比赛?
顺便说一句,它是PostgreSQL 8.4。
Answers:
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...
)更具可读性(尽管在情人眼中总是如此)。
order by
。第二个“创建”一个只包含一行和一列的虚拟表,并对其进行外部联接(没有任何“真实”联接条件),因此您总是至少要获得那一行。select *
在生产代码中使用是不好的风格。不要这样 始终列出您需要的列。select *
应该仅 在临时查询中使用。
left join
不可读?
UNION ALL
有时可能比效率更高UNION
,因为您明确地告诉查询计划者您希望UNION
ed查询中不会出现重复的行,或者您希望它们被输出。如果没有ALL
修饰符,则假定您要删除重复的行(仅返回每行中的一条),与DISTINCT
关键字非常相似,并确保可能需要对额外的结果进行重新扫描。因此ALL
,UNION
除非您特别需要输出行重复数据删除,否则请与with一起使用。
如果您只希望返回一或零行,那么这也将起作用:
SELECT
max(col1) col1,
max(col2) col2,
1 AS query_id
FROM
players
WHERE
username='foobar';
如果未找到行,则将返回一行,所有值均为null,但query_id除外。
username = 'foobar'
在这里晚了一些时间,但是这里有一个有效的语法(至少在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”的全部内容为空,将仅返回“空白”行。
请享用。/位头