SQL count(*)=1 时的聚合函数,所以只能有一个值
SQL aggregate function when count(*)=1 so there can be only one value
有时您会编写一个分组查询,其中每个组都是一行,如 having count(*) = 1
。这意味着像 min
、max
、sum
等常用的聚合函数有点毫无意义:最小值等于最大值、等于总和、等于平均值。因为只有一个值要聚合。
我通常会随意选择 min
。如果我们采用 table 将一本书映射到其作者的熟悉示例,我可能只想查询只有一个作者的书:
-- For books that have a single author, pull back that author's id.
select book_id,
min(author_id) as author_id
-- I could equally well use max(author_id) or even sum(author_id)...
from book_authors
group by book_id
having count(*) = 1
行得通,但似乎可以更好地表达。我实际上对 'minimum' 本身并不感兴趣,只是为了获得我知道存在的单一值。某些列类型(例如 Microsoft SQL Server 中的 bit
)不支持 min
聚合函数,因此您必须使用 convert(bit, min(convert(int, mycol)))
.
等变通方法
所以,我希望答案是否定的,但是有没有更好的方法来说明我的意图?
select book_id,
there_must_be_one_value_so_just_return_it(author_id) as author_id
from book_author
group by book_id
having count(*) = 1
显然,如果您不需要 count(*)=1
,那么您将不再保证单个值,并且无法使用特殊的聚合函数。编译 SQL 时可能会发现该错误。
所需的结果将等同于上面的 min
查询。
我使用的是 Microsoft SQL Server (2016),但由于这是一个相当“蓝天”的问题,我也对其他 SQL 方言的回复感兴趣。
您可以改为使用窗口化 COUNT
,然后基于它进行过滤:
WITH CTE AS(
SELECT ba.book_id,
ba.author_id,
COUNT(ba.book_id) OVER (PARTITION BY ba.book_id) AS Authors
FROM dbo.book_authors ba)
SELECT c.book_id,
c.author_id
FROM CTE c
WHERE c.Authors = 1;
另一种方法是使用相关子查询:
SELECT ba.book_id,
ba.author_id
FROM dbo.book_authors ba
WHERE EXISTS (SELECT 1
FROM dbo.book_authors e
WHERE e.book_id = ba.book_id
GROUP BY e.book_id
HAVING COUNT(*) = 1);
我还没有用相当数量的数据测试性能,但是,我 希望 对于具有良好索引 table 的相关子查询,你应该会看到更好的性能。
有时您会编写一个分组查询,其中每个组都是一行,如 having count(*) = 1
。这意味着像 min
、max
、sum
等常用的聚合函数有点毫无意义:最小值等于最大值、等于总和、等于平均值。因为只有一个值要聚合。
我通常会随意选择 min
。如果我们采用 table 将一本书映射到其作者的熟悉示例,我可能只想查询只有一个作者的书:
-- For books that have a single author, pull back that author's id.
select book_id,
min(author_id) as author_id
-- I could equally well use max(author_id) or even sum(author_id)...
from book_authors
group by book_id
having count(*) = 1
行得通,但似乎可以更好地表达。我实际上对 'minimum' 本身并不感兴趣,只是为了获得我知道存在的单一值。某些列类型(例如 Microsoft SQL Server 中的 bit
)不支持 min
聚合函数,因此您必须使用 convert(bit, min(convert(int, mycol)))
.
所以,我希望答案是否定的,但是有没有更好的方法来说明我的意图?
select book_id,
there_must_be_one_value_so_just_return_it(author_id) as author_id
from book_author
group by book_id
having count(*) = 1
显然,如果您不需要 count(*)=1
,那么您将不再保证单个值,并且无法使用特殊的聚合函数。编译 SQL 时可能会发现该错误。
所需的结果将等同于上面的 min
查询。
我使用的是 Microsoft SQL Server (2016),但由于这是一个相当“蓝天”的问题,我也对其他 SQL 方言的回复感兴趣。
您可以改为使用窗口化 COUNT
,然后基于它进行过滤:
WITH CTE AS(
SELECT ba.book_id,
ba.author_id,
COUNT(ba.book_id) OVER (PARTITION BY ba.book_id) AS Authors
FROM dbo.book_authors ba)
SELECT c.book_id,
c.author_id
FROM CTE c
WHERE c.Authors = 1;
另一种方法是使用相关子查询:
SELECT ba.book_id,
ba.author_id
FROM dbo.book_authors ba
WHERE EXISTS (SELECT 1
FROM dbo.book_authors e
WHERE e.book_id = ba.book_id
GROUP BY e.book_id
HAVING COUNT(*) = 1);
我还没有用相当数量的数据测试性能,但是,我 希望 对于具有良好索引 table 的相关子查询,你应该会看到更好的性能。