SQL 计数匹配
Posted
技术标签:
【中文标题】SQL 计数匹配【英文标题】:SQL Count Matches 【发布时间】:2020-09-07 13:16:15 【问题描述】:我有一个包含 191 个值的列表,我想与一列进行比较。我最终想要获得在我的主列表 (matches/(non-matches + NULL)
) 中有值的行的计数。
我知道我可以执行以下操作,但我想知道这是否是最有效的方法?是否可以创建一个存储值的数组并对此进行检查?不确定best practice
的执行方式是什么,我有 191 个值要检查?
我希望避免将 191 csv 放入参数中,因为这会影响格式化/可读性。有没有办法将这些值存储在数组或临时表中,这样我就可以将一个速记变量放入实际查询中?还是不管有多少值要检查,使用下面的方法/平均方法仍然是最好的方法?
SELECT
SUM(CASE WHEN COALESCE(field, '') IN (COMMA SEPARATED VALUES) THEN 1 ELSE 0 END) as matches,
COUNT(COALESCE(field)) as total_rows
FROM table
另外,我相信 COUNT(*)
和 COUNT(1)
对 NULL
字段视而不见,所以任何人都可以确认使用 COUNT(COALESCE(FIELD))
是否确保计数包括字段中的空值? p>
【问题讨论】:
【参考方案1】:Presto 不支持临时表,但您可以通过使用内联表(WITH
子句与 VALUES
结合使用)来提高查询的可读性,以避免聚合表达式中的值列表过长。
然后,您可以通过执行以下操作来计算匹配数。请注意使用FILTER
以提高可读性。
count(*) FILTER (WHERE field IN (SELECT value FROM data))
这是一个完整的例子:
WITH data(value) as (VALUES
'value1',
'value2',
...
)
SELECT
count(*) AS total_rows,
count(*) FILTER (WHERE field IN (SELECT value FROM data)) AS matches
FROM t
【讨论】:
这会为每一行运行SELECT field FROM data
还是会执行一次?如果它查询缓存,我想它只是对该查询的一次点击,但我想知道你是否知道?
运行一次。在内部,它作为“半连接”执行。引擎将运行子查询,构建一个哈希集并探测外部查询中的每个值以查看它是否包含在集合中。【参考方案2】:
我想你只是想要:
SELECT AVG(CASE WHEN field IN (COMMA SEPARATED VALUES) THEN 1.0 ELSE 0 END) as match_ratio
FROM table
【讨论】:
啊,是的——和上次一样的错误。主要关注的是要检查的 191 个值。这仍然是首选方法还是有更优化的解决方案?即使是为了可读性,因为添加 191 个值会使这很难实际遵循。道歉不清楚 - 更新 @urdearboy 。 . .in
列表中的 191 个值应该没问题。除非值已经在表中,否则很难想到另一种方法。【参考方案3】:
一个选项使用avg()
:
select avg(case when field in (<<csv list>>) then 1.0 else 0 end) rows_ratio
from mytable
使用数组来传递值可能更简单:
select avg(case when contains(<< array of values>>, field) then 1.0 else 0 end) rows_ratio
from mytable
【讨论】:
errr 我的问题表述得很糟糕。这是正确的,但不是我想要的。我对处理 191 个值的各种方法更感兴趣,这些方法不涉及我手动将它们放入公式中。本质上想知道是否有一种方法可以将它们存储在变量中,然后将变量放入查询行而不是 191 个逗号分隔值 @urdearboy:嗯,如何将值传递给查询取决于您使用的应用程序软件......您可能想向我们展示应用程序代码的相关部分。跨度>以上是关于SQL 计数匹配的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 抛出“java.sql.SQLException:列计数与第 1 行的值计数不匹配”[重复]
无论如何,为了提高 SQL 查询的性能,以按标签匹配计数查找具有顺序的行