Почему подсчет игнорирует группирование по - PullRequest
4 голосов
/ 18 мая 2019

Я не понимаю, почему мой запрос не группирует результаты подсчета по указанному мной столбцу. Вместо этого он подсчитывает все вхождения result_id в подтаблице 'un'.

Что мне там не хватает?

Полная структура моей базы данных и запрос, который я пробовал, приведены здесь:

https://www.db -fiddle.com / ж / 4HuLpTFWaE2yBSQSzf3dX4 / 4 * +1009 *

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 ]

1 голос
/ 19 мая 2019

Предполагая , у вас есть следующие ограничения PK:


CREATE TABLE combination (
  combination_id integer <b>PRIMARY KEY</b>
, ticket_id      integer
, outcomes       integer[]
);

CREATE TABLE outcome (
  outcome_id integer
, ticket_id  integer
, val        double precision
<b>, PRIMARY KEY (ticket_id, outcome_id)</b>
);

и при условии этой цели:

Дляв каждой строке таблицы combination подсчитайте количество элементов массива в outcomes, для которых в таблице есть * хотя бы одна строка с совпадающими outcome_id и ticket_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;

Plus,для него не требуется PK на outcome.Любое количество совпадающих строк по-прежнему считается 1 , поскольку EXISTS.

db <> fiddle здесь

Как всегда, лучший ответ зависит от точного определения настроек и требований.

1 голос
/ 19 мая 2019

Более простая версия ответа @forpas:

- Вам не нужно присоединяться к результатам в выражении «с».

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 облегчало отладку запросов и поддержание дальнейшей работы.

0 голосов
/ 18 мая 2019

Вам необходимо присоединиться к 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

См. Демоверсию .
Результаты:

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