Поиск недостающих заказов в столбце с помощью SQL - PullRequest
1 голос
/ 28 октября 2019

Учитывая следующую таблицу «Заказы»:

+--------------------------+
| id|order|country|cstm_id |
+--------------------------+
| 1 |O-1  |DE     |1       |
| 4 |O-2  |AT     |2       |
| 5 |O-3  |DE     |2       |
| 6 |O-5  |AT     |2       |
| 8 |O-6  |DE     |3       |
| 10|O-10 |DE     |3       |
| 11|O-11 |AT     |3       |
| 12|O-123|DE     |1       |
+--------------------------+

В столбце идентификатора и в столбце заказа отсутствуют значения.

Мне удалось использовать этот код для поиска пропущенных значений в id:

select start, stop from (
  select m.id + 1 as start,
    (select min(id) - 1 from orders as x where x.id > m.id) as stop
  from orders as m
    left outer join orders as r on m.id = r.id - 1
  where r.id is null
) as x
where stop is not null;

С результатами, как хотелось:

+------------+
| start|stop |
+------------+
| 2    |3    |
| 7    |7    |
| 9    |9    |
+------------+

Однако я столкнулся с препятствием накак сделать то же самое со столбцом заказа, так как последовательность не числовая.

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Предполагая, что начальная буква номера заказа может отличаться от 'O', используйте regexp для разделения буквенной и числовой частей и сортировки по каждой части.

with orders (id,order_num,country,cstm_id) as
     (values
             (1 , 'O-1'  , 'DE' ,1)
           , (4 , 'O-2'  , 'AT' ,2)
           , (5 , 'O-3'  , 'DE' ,2)
           , (6 , 'O-5'  , 'AT' ,2)
           , (8 , 'O-6'  , 'DE' ,3)
           , (10, 'O-10' , 'DE' ,3)
           , (11, 'O-11' , 'AT' ,3)
           , (12, 'O-123', 'DE' ,1)
    )
select *
  from orders 
 order by regexp_replace(order_num, '^([A-Z]+)-(\d+)$','\1') 
        , regexp_replace(order_num, '^([A-Z]+)-(\d+)$','\2')::integer ;
0 голосов
/ 28 октября 2019

Ваш первый запрос может быть упрощен с помощью оконных функций (и, скорее всего, он также будет быстрее):

select id + 1 as start, 
       next_id - 1 as stop
from (
  select id, 
         lead(id) over w as next_id,
         lead(id) over w - id as diff
  from orders
  window w as (order by id)
) t
where diff > 1;

Тот же подход можно использовать для значения "порядок" после очисткинечисловая часть:

with clean_ids as (
  select regexp_replace("order", '[^0-9]', '', 'g')::int as order_id
  from orders
) 
select order_id + 1 as start, 
       next_id - 1 as end
from (
  select order_id, 
         lead(order_id) over w as next_id,
         lead(order_id) over w - order_id as diff
  from clean_ids
  window w as (order by order_id)
) t
where diff > 1;

Онлайн пример: https://rextester.com/NTIEG85119

...