Минимальное и максимальное значения группируются по последовательным диапазонам - PullRequest
0 голосов
/ 12 апреля 2019

У меня есть таблица, которая сообщает мне тип ошибки и номер строки, в которой произошла ошибка. (Процесс не имеет значения в данный момент). Мне нужно сгруппировать по типу ошибки и показать начало и конец строки для каждого типа ошибки, в результате диапазон каждого типа ошибки. Мне нужно учитывать разрывы строк

Моя таблица и запросы были:

create table errors (
    err_type varchar(10),
    line integer);

insert into errors values
('type_A', 1),('type_A', 2),('type_A', 3),
('type_A', 6),('type_A', 7),
('type_B', 9),('type_B', 10),
('type_B', 12),('type_B', 13),('type_B', 14),('type_B', 15),
('type_C', 21);

select * from errors;

Мои данные:

err_type    line
----------------
type_A      1
type_A      2
type_A      3
type_A      6
type_A      7
type_B      9
type_B     10
type_B     12
type_B     13
type_B     14
type_B     15
type_C     21

Мне нужен запрос для этого:

err_type    line_start   line_end
-------------------------------
type_A      1             3
type_A      6             7
type_B      9            10
type_B     12            15
type_C     21            21

Я использую PostgreSQL, но у Oracle аналогичный синтаксис для partitioning over функциональности.

Есть предложения?

Ответы [ 3 ]

2 голосов
/ 12 апреля 2019

Вы можете создать запрос следующим образом:

with base as (
    select errors.*, 
           sign(line - 1 - lag(line, 1, 1) over (
                 partition by err_type 
                 order by line)) as is_start
    from   errors
), parts as (
    select base.*, 
           sum(is_start) over (
                 partition by err_type 
                 order by line) as part
    from   base
)
select   err_type, 
         min(line),
         max(line) 
from     parts
group by err_type, part
order by err_type, part;
0 голосов
/ 13 апреля 2019

Это проблема пробелов и островков.Я думаю, что самый простой метод - row_number() и group by:

select err_type, min(line), max(line)
from (select e.*, row_number() over (partition by err_type order by line) as seqnum
      from errors e
     ) e
group by err_type, (line - seqnum)
order by err_type, min(line);

Здесь - это скрипта db <>.

0 голосов
/ 13 апреля 2019

Если вы не хотите использовать функции окна / агг.

WITH
  table_min AS
  (
    SELECT
      a.err_type, a.line
    FROM errors a
    LEFT JOIN errors b ON a.err_type = b.err_type AND a.line  = b.line +1
    WHERE b.err_type IS NULL
  ),
  table_max AS
  (
    SELECT
      a.err_type, a.line
    FROM errors a
    LEFT JOIN errors b ON a.err_type = b.err_type AND a.line + 1 = b.line
    WHERE b.err_type IS NULL
  ),
  table_next AS
  (
    SELECT
      mx.err_type, mx.line, mi.line AS next_line_start
    FROM table_min mi
    INNER JOIN table_max mx
      ON mi.err_type = mx.err_type
      AND mi.line > mx.line
  )
SELECT
  a.err_type, a.line AS line_start, b.line AS line_end
FROM table_min a
INNER JOIN table_max b ON a.err_type = b.err_type AND a.line <= b.line
LEFT JOIN table_next n ON a.err_type = n.err_type
WHERE
  (b.line = n.line OR n.next_line_start = a.line OR n.line IS NULL)
ORDER BY a.line
...