Sql查询在同一查询中查找具有差异条件的计数和总计数

Posted

技术标签:

【中文标题】Sql查询在同一查询中查找具有差异条件的计数和总计数【英文标题】:Sql query to find count with a difference condition and total count in the same query 【发布时间】:2015-05-29 07:07:09 【问题描述】:

这是我的示例表

Logs
user_id, session_id, search_query,  action
1, 100, dog, A
1, 100, dog, B
2, 101, cat, A
3, 102, ball, A
3, 102, ball, B
3, 102, kite, A
4, 103, ball, A
5, 104, cat, A

在哪里 miss = 对于相同的 user_id 和相同的会话 id ,如果操作 A 后面没有操作 B,则称为未命中。 注意:动作 B 只能在动作 A 发生后发生。

我能够找到所有用户和会话中每个唯一 search_query 的未命中计数。

SELECT l1.search_query, count(l1.*) as misses
FROM logs l1
WHERE NOT EXISTS
    (SELECT NULL FROM logs l2
     WHERE l1.user_id = l2.user_id
     AND l1.session_id = l2.session_id
     AND l1.session_id != ''
     AND l2.action = 'B'
     AND l1.action = 'A')
AND l1.action='A'
AND l1.search_query != ''
GROUP BY v1.search_query
order by misses desc;

我正在尝试为每个唯一的 search_query 找到miss_percentage=(未命中数/总行数)*100 的值。我不知道如何在同一个查询中找到有条件的计数和没有该条件的计数。任何帮助都会很棒。

expected output:
cat 100
kite 100
ball 50 

【问题讨论】:

【参考方案1】:

一种方法是将EXISTS 移动到计数中

SELECT l1.search_query, count(case when NOT EXISTS
    (SELECT 1 FROM logs l2
     WHERE l1.user_id = l2.user_id
     AND l1.session_id = l2.session_id
     AND l1.search_query = l2.search_query
     AND l2.action = 'B'
     AND l1.action = 'A') then 1 else null end
)*100.0/count(*) as misses
FROM logs l1
WHERE l1.action='A'
AND l1.search_query != ''
GROUP BY l1.search_query
order by misses desc;

这会产生所需的结果,但如果没有发现任何遗漏,也会产生零。这可以通过HAVING 子句或后处理来删除。

请注意,我还添加了缺少的子句l1.search_query = l2.search_query,否则它会将风筝计为成功,因为在同一会话中有一行带有 B。

【讨论】:

对不起,之前忘了提这个。我在 amazon-redshift 表中运行此查询。我收到以下错误。 An error occurred when executing the SQL command: SELECT l1.search_query, count(case when NOT EXISTS (SELECT 1 FROM logs l2 WHERE l1.user_id = l... ERROR: This type of correlated subquery pattern is not supported due to internal error [SQL State=XX000] 【参考方案2】:

我认为你只需要在这里使用 case 语句。如果我正确理解了您的问题..那么解决方案将是这样的 -

WITH summary
AS (
    SELECT user_id
        ,session_id
        ,search_query
        ,count(1) AS total_views
        ,sum(CASE 
                WHEN action = 'A'
                    THEN 1
                ELSE 0
                END) AS action_a
        ,sum(CASE 
                WHEN action = 'B'
                    THEN 1
                ELSE 0
                END) AS action_b
    FROM logs l
    GROUP BY user_id
        ,session_id
        ,search_query
    )
SELECT search_query
    ,(sum(action_a - action_b) / sum(action_a)) * 100 AS miss_percentage
FROM summary
GROUP BY search_query;

【讨论】:

【参考方案3】:

您始终可以创建两个查询,并通过连接将它们合并为一个。然后您可以在桥接(或连接)SQL 语句中进行计算。

在 MS-SQL 兼容的 SQL 中,这将是:

SELECT ActiontypeA,countedA,isNull(countedB,0) as countedB, 
   (countedA-isNull(countedB,0))*100/CountedA as missed
    FROM (SELECT search_query as actionTypeA, count(*) as countedA 
          FROM logs WHERE Action='A' GROUP BY actionType
         ) as TpA
    LEFT JOIN
         (SELECT search_query as actionTypeB, count(*) as countedB 
          FROM logs WHERE Action='B' GROUP BY actionType
         ) as TpB
ON TpA.ActionTypeA = TpB.ActiontypeB

LEFT JOIN 需要从“A”结果中选择所有活动 (search_query),并仅将它们加入到“B”结果中 B 可用的活动中。 由于这是非常基本的 SQL(并且通过 SQL 引擎进行了很好的优化),我建议尽可能地防止 WHERE EXISTSIsNull() 函数是一个 MS-SQL 函数,用于将 NULL 值强制转换为可用于计算的 int(0) 值。

终于可以过滤了

WHERE missed>0

得到最终结果。

【讨论】:

如果问题是关于 PostgreSQL,为什么要提出 MSSQL 解决方案? SQL 跨引擎非常兼容。这个答案有助于跨系统的 SQL 概念。我只能在 MS-SQL 上测试解决方案。我对这个投反对票不太满意... SQL 是一个标准,而 MSSQL 以偏离它而闻名,无论如何远远超过 PostgreSQL。后者没有用于所述目的的isNull() 函数,而是使用coalesce()。无论您是在 PostgreSQL 还是 MSSQL 中运行,您的代码都存在错误。否决票是因为答案不充分。

以上是关于Sql查询在同一查询中查找具有差异条件的计数和总计数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 sql 中的单个查询获取项目计数和总计数?

无论如何,为了提高 SQL 查询的性能,以按标签匹配计数查找具有顺序的行

是否有任何其他选项可以从表中获取总计数和同一查询中列的不同计数?

为啥在 oracle SQL 中,在条件相差很大的情况下,对同一列执行具有两个不同值的查询所花费的时间

如何使用具有多个连接的 SQL 查询并使用休眠计数

SQL 查询重新计算运行总计