2009-04-29 21 views
1

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.Séquence de vérification avec requête SQL

select WebStoreID, min(webordernumber), max(webordernumber), count(webordernumber) 
from orders 
where ordertype = 'WEB' 
group by WebStoreID 

Je peux vérifier toutes les commandes sont présentes avec cette requête. numéro de page Web est le numéro de 1 ... n.

Comment puis-je écrire une requête pour trouver des ordres manquants sans rejoindre une table temporaire/différente?

+0

Il est très difficile de sélectionner des données qui est en réalité pas là. –

+0

De commentaires, il devient clair que vous exécutez ici SQL Server. Vous auriez vraiment dû le dire dans votre question, ou utilisé une balise pour l'indiquer ([SQL] est une balise générique pour les questions SQL, pas pour SQL Server). –

Répondre

6

Vous pouvez joindre la table sur elle-même pour détecter les lignes qui n'ont pas rangée 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 il ne serait pas détecter les doublons.

+0

Peut vouloir afficher: SELECT cur.webordernumber + 1 AS Missing_OrderNumber, cur. * from ... Pour une séquence de: 101, 102, 105 - seulement 103 apparaîtraient manquants. Je ne sais pas s'il est important d'afficher 104 également. – JeffO

4

Je voudrais faire une table auxiliaire de "tous les entiers de 1 à n" (voir http://www.sql-server-helper.com/functions/integer-table.aspx pour certaines façons de le faire avec une fonction SQL Server, mais puisque c'est quelque chose dont vous aurez besoin à plusieurs reprises, je le ferais dans une vraie table de toute façon, et avec n'importe quel moteur SQL, il est facile de faire cela, juste une fois), puis d'utiliser une requête imbriquée, SELECT value FROM integers WHERE value NOT IN (SELECT webordernumber FROM orders) & c. Voir aussi http://www.sqlmag.com/Article/ArticleID/99797/sql_server_99797.html pour un problème similaire au vôtre, "détecter des lacunes dans une séquence de nombres".

+0

+ Merci pour les liens intéressants. – THEn

1

Si votre base de données prend en charge les fonctions d'analyse, vous pouvez alors utiliser quelque chose comme une requête:

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 affiche les lacunes par exemple

prev+1 curr-1 
------ ------ 
    3  7 

signifierait que les numéros 3 à 7 inclus sont manquants.

+0

Merci. Qu'est-ce que nvl? Je ne peux pas le trouver sur MSSQL? – THEn

+0

Désolé, j'ai écrit ma réponse sous le malentendu que c'était une question d'Oracle - NVL est Oracle parle pour COALESCE. J'ai mis à jour ma réponse pour utiliser COALESCE (qui si vous n'avez pas est équivalent à CASE WHEN param1 n'est pas NULL ALORS param1 ELSE param2 END) –

2

Si vous avez la fonction de rang() mais pas la fonction lag() (en d'autres termes, SQL Server), vous pouvez l'utiliser (suggérée par 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 

... 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)