为什么计数忽略分组依据

时间:2019-05-18 12:28:06

标签: sql postgresql count case postgresql-9.4

我不明白为什么我的查询不按我指定的列对计数结果进行分组。相反,它会计算“ un”子表中所有result_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

3 个答案:

答案 0 :(得分:1)

假设,您具有以下PK约束:

tcourses: async (user, args, { models }) => {
      return await models.TCourses.findAll({
        where: { UserId: user.id },
        include: [{model: models.Course, as: 'Course', include: [{model: models.Category, as: 'Category'}]}]
      })
    },

假设此目标:

对于表 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_id-和ticket_id中的1}}。

假设高于PK,这将简化为一个更简单的查询:

outcome

有了索引支持,这种替代方法可能会更快:

val >= 1.3

此外,它不需要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; 上的PK。由于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; ,任何数量的匹配行仍计为 1

db <>提琴here

一如既往,最佳答案取决于对设置和要求的精确定义。

答案 1 :(得分:1)

@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子句中使用完整的字段名可以使查询更易于调试和维护。

答案 2 :(得分:0)

您还需要加入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