Vérification d'une séquence avec une requête SQL
-
03-07-2019 - |
Question
J'ai une commande de table qui conserve toutes les commandes de tous nos magasins. J'ai écrit une requête pour vérifier les ordres de séquence pour chaque magasin. Ça ressemble à ça.
select WebStoreID, min(webordernumber), max(webordernumber), count(webordernumber)
from orders
where ordertype = 'WEB'
group by WebStoreID
Je peux vérifier que toutes les commandes sont présentes avec cette requête. le numéro d'ordre Web est le numéro 1 ... n.
Comment puis-je écrire une requête pour trouver les commandes manquantes sans rejoindre la table temporaire / différente?
La solution
Vous pouvez joindre la table sur elle-même pour détecter les lignes qui n'ont pas de ligne précédente:
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
Cela permettrait de détecter les lacunes dans la séquence 1 ... n, mais pas les doublons.
Autres conseils
Je ferais une table auxiliaire de "tous les entiers de 1 à n" (voir http://www.sql-server-helper.com/ functions / integer-table.aspx pour certaines manières de le créer avec une fonction SQL Server, mais comme c'est quelque chose dont vous aurez besoin encore et encore, j'en ferais de toute façon une vraie table, et avec n'importe quel moteur SQL, c'est facile à faire, juste une fois) puis utilisez une requête imbriquée, SELECT valeur FROM nombres entiers WHERE valeur NOT IN (SELECT ordre Web ordre FROM ordre)
& amp; c. Voir également http://www.sqlmag.com/Article/Article/ArticleID/99797/ sql_server_99797.html pour un problème similaire au vôtre, "détection des lacunes dans une séquence de chiffres".
Si vous avez la fonction rank () mais pas la fonction lag () (en d'autres termes, SQL Server), vous pouvez l'utiliser (suggéré par http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-programming / 10594 / Retour dans la séquence ):
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
... ou, pour inclure les "limites extérieures":
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)
Si votre base de données prend en charge les fonctions analytiques, vous pouvez utiliser une requête du type:
select prev+1, curr-1 from
( select webordernumber curr,
coalesce (lag(webordernumber) over (order by webordernumber), 0) prev
from orders
)
where prev != curr-1;
La sortie montrera les lacunes, par exemple.
prev+1 curr-1
------ ------
3 7
signifierait que les numéros 3 à 7 inclus sont manquants.