Группировать и считать по значению другого столбца - PullRequest
0 голосов
/ 11 сентября 2018

У меня есть таблица, как показано ниже:

CREATE TABLE public.test_table
(
    "ID" serial PRIMARY KEY NOT NULL,
    "CID" integer NOT NULL,
    "SEG" integer NOT NULL,
    "DDN" character varying(3) NOT NULL
)

и данные выглядят так:

ID  CID SEG DDN
1   1   1   "711"
2   1   2   "800"
3   1   3   "124"
4   2   1   "711"
5   3   1   "711"
6   3   2   "802"
7   4   1   "799"
8   5   1   "799"
9   5   2   "804"
10  6   1   "799"

Мне нужно сгруппировать эти данные по столбцу CID, и получить количество столбцов зависит от первых значений столбцов DDN, но при этом должно быть две разные информации, если их больше 1 или нет.

Мне очень жаль, если не смог объяснить четко. Позвольте мне показать вам, что мне нужно ..

DDN END TRA
711 1   2
799 2   1

Как видите, DDN: 711 имеет 1 запись с одним счетом (ID: 4). Это конец колонки. Но у 2 раз есть многократное количество SEG (ID: 1to3 и ID: 5to6). Это столбец TRA.

Я не могу быть уверен, какой столбец должен быть в предложении группы!

Мое решение:

Только что нашел решение, как показано ниже

WITH x AS (
    SELECT
        (SELECT t1."DDN" FROM public.test_table AS t1
         WHERE t1."CID"=t."CID" AND t1."SEG"=1) AS ddn,
        COUNT("CID") AS seg_count       
    FROM public.test_table AS t
    GROUP BY "CID"
)

SELECT ddn, COUNT(seg_count) AS "TOTAL",    
    SUM(CASE WHEN x.seg_count=1 THEN 1 ELSE 0 END) as "END",
    SUM(CASE WHEN x.seg_count>1 THEN 1 ELSE 0 END) as "TRA"
FROM x
GROUP BY ddn;

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Эквивалент, более быстрый запрос:

SELECT "DDN"
     , COUNT(*) AS "TOTAL"
     , COUNT(*) FILTER (WHERE seg_count = 1) AS "END"
     , COUNT(*) FILTER (WHERE seg_count > 1) AS "TRA"
FROM  (
   SELECT DISTINCT ON ("CID")
         "DDN"          -- assuming min "SEG" is always 1
       , COUNT(*) OVER (PARTITION BY "CID") AS seg_count
   FROM   test_table
   ORDER  BY "CID", "SEG"
   ) sub
GROUP  BY "DDN";

дБ <> скрипка здесь

Примечания:

  • CTE обычно медленнее и должны использоваться только в случае необходимости в Postgres.

  • Это эквивалентно запросу в вопросе при условии , что минимальное «SEG» на «CID» всегда 1 - так как этот запрос возвращает строку с минимальный "SEG", в то время как ваш запрос возвращает тот с "SEG" = 1. Как правило, вы хотите, чтобы «первый» сегмент и мой запрос выполняли это требование более надежно, но из вопроса не ясно.

  • COUNT(*) немного быстрее, чем COUNT(column) и эквивалентен, но не включает значения NULL (применимо здесь). Связанный:

  • О DISTINCT ON:

  • Совокупный синтаксис FILTER требует Postgres 9.4 +:

0 голосов
/ 11 сентября 2018

Вот решение, которое я предлагаю, вопрос может быть упрощен, я думаю.

CREATE TABLE test_table
(
    ID serial PRIMARY KEY NOT NULL,
    CID integer NOT NULL,
    SEG integer NOT NULL,
    DDN character varying(3) NOT NULL
);



insert into test_table(CID,SEG,DDN)
values
(   1,   1,   '711'),
(   1,   2,   '800'),
(   1,   3,   '124'),
(   2,   1,   '711'),
(   3,   1,   '711'),
(   3,   2,   '802'),
(   4,   1,   '799'),
(   5,   1,   '799'),
(   5,   2,   '804'),
(   6,   1,   '799');


with summary as (with ddn_t as (select cid,ddn,row_number() OVER( PARTITION BY cid)from test_table)
select a.cid,count(distinct a.ddn),b.ddn
 from ddn_t a 
 join ddn_t b on b.cid=a.cid and b.row_number=1
group by a.cid, b.ddn)
select ddn,
sum (case when count >1 then 1 else 0 end) as TRA,
sum (case when count = 1 then 1 else 0 end) as END
from summary
group by ddn;
...