sql как выбрать следующий или последний ряд групп с двумя или более рядами - PullRequest
0 голосов
/ 16 января 2020

У меня есть таблица выполненных действий над разными экземплярами объекта, которые имеют разные версии. Если я сгруппирую действия для экземпляра и версии, с этим SELECT (сокращенно)

SELECT instance, version, COUNT(id) AS cnt
FROM actions
WHERE status=0
  AND version IS NOT NULL
GROUP BY instance, version

я получу эту таблицу (сокращенно)

 instance | version | cnt 
----------+---------+------
  1021    | 18.1    | 263   
  1021    | 18.2    | 422  
  1021    | 19.1    | 949  
  1191    | 18.2    | 28
  1195    | 18.1    | 584  
  1195    | 18.2    | 176
  1195    | 18.3    | 437
  1195    | 19.1    | 152
  1195    | 19.2    | 545  
  1195    | 19.3    | 399
  1196    | 18.3    | 844 
  1196    | 19.1    | 800 
  1197    | 18.3    | 2 
  1201    | 18.1    | 471
  1201    | 18.2    | 584
  1201    | 18.3    | 553
  1201    | 19.1    | 498
  1201    | 19.2    | 203
  1201    | 19.3    | 36
  1208    | 18.1    | 444
  1208    | 18.2    | 548
  1208    | 18.3    | 31
  1208    | 19.2    | 357
  1210    | 19.1    | 514
  1211    | 18.2    | 341
  1211    | 19.1    | 531
  ....

сейчас, я хочу строку, соответствующую до последней версии для экземпляров, имеющих более одной версии.

Итак, в этом примере мне нужно выбрать строки

 instance | version | cnt 
----------+---------+------
  1021    | 18.2    | 422  
  1195    | 19.2    | 545  
  1196    | 18.3    | 844 
  1201    | 19.2    | 203
  1208    | 18.3    | 31
  1211    | 18.2    | 341
  ...

Я попытался GROUP BY instance HAVING count(*) >= 2, чтобы начать фильтруя результаты, но он подсчитывает исходные строки, а не результирующие строки после первого GROUP BY instance, version.

Любой намек на то, как этого добиться?

Ответы [ 3 ]

1 голос
/ 16 января 2020

Вы можете использовать оконные функции:

SELECT iv.*
FROM (SELECT instance, version, COUNT(id) AS cnt,
             ROW_NUMBER() OVER (PARTITION BY instance ORDER BY version DESC) as seqnum
      FROM actions
      WHERE status = 0 AND
            version IS NOT NULL
      GROUP BY instance, version
     ) iv
WHERE seqnum = 2;
1 голос
/ 16 января 2020

Предполагая, что сокращенные результаты сохраняются в тесте временной таблицы. Следующий запрос даст вам ожидаемый результат.

select * from test where (instance,version)in
(select instance,max(version) as version from test A where exists 
(select max(version) as version from test B where A.instance=B.instance and A.version<B.version group by instance) group by instance)

Ouput

instance version cnt
1021      18.2   422
1195      19.2   545
1196      18.3   844
1201      19.2   203
1208      18.3   31
1211      18.2   341
1 голос
/ 16 января 2020

Кажется, вам нужно (без оптимизации!)

WITH 
cte1 AS ( SELECT instance, version, COUNT(id) AS cnt
          FROM actions
          WHERE status=0
            AND version IS NOT NULL
          GROUP BY instance, version ),
cte2 AS ( SELECT instance, MAX(version) version
          FROM cte1
          GROUP BY instance ),
cte3 AS ( SELECT instance, MAX(version) version
          FROM cte1
          LEFT JOIN cte2 USING (instance, version)
          WHERE cte2.instance IS NULL
          GROUP BY instance )
SELECT cte1.*
FROM cte1
JOIN cte3 USING (instance, version)

скрипка

...