单独的子选择以获得多个计数?
Separate subselects to get multiple counts?
我有这个查询:
SELECT
(SELECT COUNT(media_id) FROM likes WHERE like_state = true AND media_id = ?) AS likes,
(SELECT COUNT(media_id) FROM likes WHERE like_state = false AND media_id = ?) AS dislikes,
(SELECT media_views FROM media_thumbnail WHERE media_id = ?) AS views;
它工作正常,但我不确定这是否是最好的方法。有什么建议吗?
我认为这不需要任何解释,但是...它计算了 like_state
函数中有多少喜欢或不喜欢(true
= 喜欢,false
= 不喜欢)和 returns 相关视频的观看次数。
你的查询很好,虽然我更倾向于把它写成:
SELECT SUM( (l.like_state = true)::int ) as likes,
SUM( (l.like_status = false)::int ) as dislikes,
MAX(mt.media_views) as media_views
FROM likes l CROSS JOIN
(SELECT media_views FROM media_thumbnail WHERE media_id = ?
) mt
WHERE l.media_id = ?;
这节省了一次扫描 likes
table 的开销。
在 table likes
上使用带有两个计数的单个 SELECT
绝对比两个单独的 SELECT
:
更快
SELECT COUNT( like_state OR NULL) AS likes
, COUNT(NOT like_state OR NULL) AS dislikes
,(SELECT media_views FROM media_thumbnail WHERE media_id = ?) AS views
FROM likes
WHERE media_id = ?;
此查询与不相关的子查询之间存在 corner-case 差异,您的原始查询具有两个隐式 CROSS JOIN
(FROM
列表中的逗号 ,
几乎与 CROSS JOIN
相同)以及戈登对最后一个子查询的 CROSS JOIN
的回答。
前两个子查询总是return一行,所以一个CROSS JOIN
不能消去结果。
但是第三个查询可能找不到给定的 media_id
in table media_thumbnail
and return no row。 CROSS JOIN
导致整个查询 no row
。
我在 SELECT
列表中使用子查询的查询将 无行 转换为空值,并且仍然 return 是一个结果行。 LEFT JOIN ... ON true
:
也可以达到同样的效果
如果 return 超过一行,我在 SELECT
中的子查询会引发异常 - 如果 media_thumbnail.media_id
定义为 UNIQUE
或 [=30,则不会发生这种情况=],可能不应该在任何情况下都不会发生。
关于条件计数:
漂亮干净的语法将带有 FILTER
子句:
SELECT COUNT(*) FILTER (WHERE like_state) AS likes
, COUNT(*) FILTER (WHERE NOT like_state) AS dislikes
...
有点冗长,但可能更容易阅读。性能基本相同
我有这个查询:
SELECT
(SELECT COUNT(media_id) FROM likes WHERE like_state = true AND media_id = ?) AS likes,
(SELECT COUNT(media_id) FROM likes WHERE like_state = false AND media_id = ?) AS dislikes,
(SELECT media_views FROM media_thumbnail WHERE media_id = ?) AS views;
它工作正常,但我不确定这是否是最好的方法。有什么建议吗?
我认为这不需要任何解释,但是...它计算了 like_state
函数中有多少喜欢或不喜欢(true
= 喜欢,false
= 不喜欢)和 returns 相关视频的观看次数。
你的查询很好,虽然我更倾向于把它写成:
SELECT SUM( (l.like_state = true)::int ) as likes,
SUM( (l.like_status = false)::int ) as dislikes,
MAX(mt.media_views) as media_views
FROM likes l CROSS JOIN
(SELECT media_views FROM media_thumbnail WHERE media_id = ?
) mt
WHERE l.media_id = ?;
这节省了一次扫描 likes
table 的开销。
在 table likes
上使用带有两个计数的单个 SELECT
绝对比两个单独的 SELECT
:
SELECT COUNT( like_state OR NULL) AS likes
, COUNT(NOT like_state OR NULL) AS dislikes
,(SELECT media_views FROM media_thumbnail WHERE media_id = ?) AS views
FROM likes
WHERE media_id = ?;
此查询与不相关的子查询之间存在 corner-case 差异,您的原始查询具有两个隐式 CROSS JOIN
(FROM
列表中的逗号 ,
几乎与 CROSS JOIN
相同)以及戈登对最后一个子查询的 CROSS JOIN
的回答。
前两个子查询总是return一行,所以一个CROSS JOIN
不能消去结果。
但是第三个查询可能找不到给定的 media_id
in table media_thumbnail
and return no row。 CROSS JOIN
导致整个查询 no row
。
我在 SELECT
列表中使用子查询的查询将 无行 转换为空值,并且仍然 return 是一个结果行。 LEFT JOIN ... ON true
:
如果 return 超过一行,我在 SELECT
中的子查询会引发异常 - 如果 media_thumbnail.media_id
定义为 UNIQUE
或 [=30,则不会发生这种情况=],可能不应该在任何情况下都不会发生。
关于条件计数:
漂亮干净的语法将带有 FILTER
子句:
SELECT COUNT(*) FILTER (WHERE like_state) AS likes
, COUNT(*) FILTER (WHERE NOT like_state) AS dislikes
...
有点冗长,但可能更容易阅读。性能基本相同