Проверка последовательности с помощью SQL-запроса
-
03-07-2019 - |
Вопрос
У меня есть таблица заказов, в которой хранятся все заказы из всех наших магазинов.Я написал запрос для проверки последовательности заказов для каждого магазина.Это выглядит примерно так.
select WebStoreID, min(webordernumber), max(webordernumber), count(webordernumber)
from orders
where ordertype = 'WEB'
group by WebStoreID
Я могу проверить, что все заказы присутствуют в этом запросе.номер веб-заказа - это число от 1...n.
Как я могу написать запрос для поиска недостающих заказов без присоединения к временной / другой таблице?
Решение
Вы могли бы объединить таблицу саму по себе, чтобы обнаружить строки, у которых нет предыдущей строки:
select cur.*
from orders cur
left join orders prev
on cur.webordernumber = prev.webordernumber + 1
and cur.webstoreid = prev.webstoreid
where cur.webordernumber <> 1
and prev.webordernumer is null
Это позволило бы обнаружить пробелы в последовательности 1 ... n, но не привело бы к обнаружению дубликатов.
Другие советы
Я бы составил вспомогательную таблицу "всех целых чисел от 1 до n" (см. http://www.sql-server-helper.com/functions/integer-table.aspx для некоторых способов сделать это с помощью функции SQL Server, но поскольку это то, что вам будет нужно снова и снова, я бы все равно превратил это в реальную таблицу, и с любым движком SQL это легко сделать, только один раз) затем используйте вложенный запрос, SELECT value FROM integers WHERE value NOT IN (SELECT webordernumber FROM orders)
иc.Также смотрите http://www.sqlmag.com/Article/ArticleID/99797/sql_server_99797.html для задачи, похожей на вашу, "обнаружение пробелов в последовательности чисел".
Если у вас есть функция rank(), но нет функции lag() (другими словами, SQL Server), вы можете использовать это (предложено http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-programming/10594/Return-gaps-in-a-sequence):
create table test_gaps_in_sequence (x int)
insert into test_gaps_in_sequence values ( 1 )
insert into test_gaps_in_sequence values ( 2 )
insert into test_gaps_in_sequence values ( 4 )
insert into test_gaps_in_sequence values ( 5 )
insert into test_gaps_in_sequence values ( 8 )
insert into test_gaps_in_sequence values ( 9 )
insert into test_gaps_in_sequence values ( 12)
insert into test_gaps_in_sequence values ( 13)
insert into test_gaps_in_sequence values ( 14)
insert into test_gaps_in_sequence values ( 29)
...
select lower_bound
, upper_bound
from (select upper_bound
, rank () over (order by upper_bound) - 1 as upper_rank
from (SELECT x+n as upper_bound
from test_gaps_in_sequence
, (SELECT 0 n
UNION
SELECT -1
) T
GROUP BY x+n
HAVING MAX(n) = -1
) upper_1
) upper_2
, (select lower_bound
, rank () over (order by lower_bound) as lower_rank
from (SELECT x+n as lower_bound
from test_gaps_in_sequence
, (SELECT 0 n
UNION
SELECT 1
) T
GROUP BY x+n
HAVING MIN(n) = 1
) lower_1
) lower_2
where upper_2.upper_rank = lower_2.lower_rank
order by lower_bound
...или включить "внешние пределы":
select lower_bound
, upper_bound
from (select upper_bound
, rank () over (order by upper_bound) - 1 as upper_rank
from (SELECT x+n as upper_bound
from test_gaps_in_sequence
, (SELECT 0 n
UNION
SELECT -1
) T
GROUP BY x+n
HAVING MAX(n) = -1
) upper_1
) upper_2
full join (select lower_bound
, rank () over (order by lower_bound) as lower_rank
from (SELECT x+n as lower_bound
from test_gaps_in_sequence
, (SELECT 0 n
UNION
SELECT 1
) T
GROUP BY x+n
HAVING MIN(n) = 1
) lower_1
) lower_2
on upper_2.upper_rank = lower_2.lower_rank
order by coalesce (lower_bound, upper_bound)
Если ваша база данных поддерживает аналитические функции, тогда вы могли бы использовать запрос что-то вроде:
select prev+1, curr-1 from
( select webordernumber curr,
coalesce (lag(webordernumber) over (order by webordernumber), 0) prev
from orders
)
where prev != curr-1;
На выходе будут показаны пробелы, например
prev+1 curr-1
------ ------
3 7
это означало бы, что цифры с 3 по 7 включительно отсутствуют.