【问题标题】:Why count ignores grouping by为什么 count 忽略分组依据
【发布时间】:2019-10-05 12:36:11
【问题描述】:

我不明白为什么我的查询没有按我指定的列对计数结果进行分组。相反,它会计算“un”子表中所有出现的结果 ID。

我错过了什么?

我的示例数据库的完整结构和我尝试过的查询在这里:

https://www.db-fiddle.com/f/4HuLpTFWaE2yBSQSzf3dX4/4

CREATE TABLE combination (
    combination_id integer,
    ticket_id integer,
    outcomes integer[]
);
CREATE TABLE outcome (
outcome_id integer,
ticket_id integer,
val double precision
);

insert into combination 
values
(510,188,'{52,70,10}'),
(511,188,'{52,56,70,18,10}'),
(512,188,'{55,70,18,10}'),
(513,188,'{54,71,18,10}'),

(514,189,'{52,54,71,18,10}'),
(515,189,'{55,71,18,10,54,56}')
;

insert into outcome
values
(52,188,1.3),
(70,188,2.1),
(18,188,2.6),
(56,188,2),
(55,188,1.1),
(54,188,2.2),
(71,188,3),
(10,188,0.5),

(54,189,2.2),
(71,189,3),
(18,189,2.6),
(55,189,2)

with un AS (
      SELECT combination_id, unnest(outcomes) outcome
      FROM combination c JOIN
           outcome o
           on o.ticket_id = c.ticket_id
      GROUP BY 1,2
     ) 
SELECT combination_id, cnt
FROM (SELECT un.combination_id,
             COUNT(CASE WHEN o.val >= 1.3 THEN 1 END) as cnt
      FROM un JOIN
           outcome o
           on o.outcome_id = un.outcome 
      GROUP BY 1
     ) x
GROUP BY 1, 2
ORDER BY  1

预期结果应该是:

510 2
511 4
512 2
513 3
514 4
515 4

【问题讨论】:

  • 表定义应该在您的问题中,而不仅仅是在需要从多个来源执行脚本的小提琴中。
  • 好的,更新后
  • 您能用简单的英语解释一下您要计算的确切内容吗? “预期结果”中的514 4 似乎没有加起来。应该是514 3,对吧?最佳查询取决于实际表定义,还显示约束(最重要的是PK、FK、UNIQUE)和有关数据分布的信息...
  • 现在我意识到我错过了组合 514 和 515 的结果表中的一些条目,这就是存在差异的原因。明天我会更新我的帖子并检查您的答案,因为手机不舒服。提前致谢。

标签: sql postgresql count case postgresql-9.4


【解决方案1】:

您还需要加入ticket_id

with un AS (
      SELECT c.combination_id, c.ticket_id, unnest(c.outcomes) outcome
      FROM combination c JOIN outcome o
      on o.ticket_id = c.ticket_id
      GROUP BY 1,2,3
     ) 
SELECT combination_id, cnt
FROM (SELECT un.combination_id, un.ticket_id,
             COUNT(CASE WHEN o.val >= 1.3 THEN 1 END) as cnt
      FROM un JOIN outcome o
      on o.outcome_id = un.outcome and o.ticket_id = un.ticket_id 
      GROUP BY 1,2
     ) x
GROUP BY 1, 2
ORDER BY  1

请参阅demo
结果:

> combination_id | cnt
> -------------: | --:
>            510 |   2
>            511 |   4
>            512 |   2
>            513 |   3
>            514 |   3
>            515 |   4

【讨论】:

  • 谢谢! ,尽管我错过了组合 514 和 515 的结果表中的几个条目,但您的答案计数正确:) 但是这对我来说非常混乱。为什么它需要不那么严格的分组才能按我的预期计算?简单来说——一张票可以有多种组合,但特定的combination_id只能在一张票上,那么还需要包含票号有什么意义呢?
  • 为什么它需要不那么严格的分组才能按我的预期计算?它需要更严格的分组,这就是额外条件的作用。它也与门票相匹配。没有它,有些组合你不想被计算在内。
  • 我不明白,为什么不加入ticket_id 它会计算来自其他组合的记录,而它应该已经按它们分组,因为我使用了group by combination_id?如果一张票中有重复的结果但组合不同,为什么ticket_id 会发生如此大的变化?请以某种方式逐步向我解释这一点,因为此时这对我来说是不合逻辑的
  • 这一切都与分组前获取的行有关。当您只有 on o.outcome_id = un.outcome 时,会有更多行包含不应计算的组合,这意味着属于不同工单的组合。当您为连接设置正确的条件时:on o.outcome_id = un.outcome and o.ticket_id = un.ticket_id 您将获得更少的行,因此将组合限制为仅有效的组合。然后你应用分组来计算有效行数。
【解决方案2】:

假设,您有以下 PK 约束:


CREATE TABLE combination (
  combination_id integer PRIMARY KEY
, ticket_id      integer
, outcomes       integer[]
);

CREATE TABLE outcome (
  outcome_id integer
, ticket_id  integer
, val        double precision
, PRIMARY KEY (ticket_id, outcome_id)
);

并且假设这个目标:

对于表combination中的每一行,计算outcomes中至少有一行匹配outcome_idticket_id在表outcome中的数组元素的数量- 和val >= 1.3

假设以上 PK,这会归结为一个更简单的查询:

SELECT c.combination_id, count(*) AS cnt
FROM   combination c
JOIN   outcome     o USING (ticket_id)
WHERE  o.outcome_id = ANY (c.outcomes)
AND    o.val >= 1.3
GROUP  BY 1
ORDER  BY 1;

如果有索引支持,这个替代方案可能会更快:

SELECT c.combination_id, count(*) AS cnt
FROM   combination c
CROSS  JOIN LATERAL unnest(c.outcomes) AS u(outcome_id)
WHERE  EXISTS (
   SELECT
   FROM   outcome o
   WHERE  o.outcome_id = u.outcome_id
   AND    o.val >= 1.3
   AND    o.ticket_id  = c.ticket_id   -- ??
   )
GROUP  BY 1
ORDER  BY 1;

另外,它不需要outcome 上的PK。由于EXISTS,任何数量的匹配行仍然算作1

db小提琴here

与往常一样,最佳答案取决于确切设置和要求的定义。

【讨论】:

    【解决方案3】:

    @forpas 答案的更简单版本:

    -- 你不需要在“with”语句中加入结果。

    with un AS (
    SELECT combination_id, ticket_id, unnest(outcomes) outcome
    FROM combination c
    -- no need to join to outcomes here
    
    GROUP BY 1,2,3
    ) 
    
    SELECT combination_id, cnt FROM 
    (
    SELECT un.combination_id,
    COUNT(CASE WHEN o.val >= 1.3 THEN 1 END) as cnt
    
    FROM un
    JOIN outcome o on o.outcome_id = un.outcome
                and o.ticket_id = un.ticket_id
    
    GROUP BY 1
    )x
    
    GROUP BY 1,2
    ORDER BY  1
    

    正如其他人指出的那样,根据您的输入数据,514 的预期结果应该是 3。

    我还想建议,在 group by 和 order by 子句中使用完整的字段名称可以使查询更易于调试和维护。

    【讨论】:

    • 谢谢,我确实错过了结果表中 514 和 515 组合的几个条目,无论如何你的答案都算正确。然而,这对我来说非常混乱。为什么它需要不那么严格的分组才能按我的预期计算?简单来说 - 一张票可以有多种组合,但特定的 combination_id 只能出现在一张票上,那么还需要包含票号有什么意义?
    • 我将ticket_id 上的连接移到了下方的select 语句中。 with 子句仅用于取消嵌套结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-19
    • 2021-09-09
    • 2016-09-14
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    相关资源
    最近更新 更多