Verifica della sequenza con query SQL
-
03-07-2019 - |
Domanda
Ho un ordine da tavolo che conserva tutti gli ordini da tutti i nostri negozi. Ho scritto una query per verificare gli ordini di sequenza per ciascun negozio. Sembra così.
select WebStoreID, min(webordernumber), max(webordernumber), count(webordernumber)
from orders
where ordertype = 'WEB'
group by WebStoreID
Posso verificare che tutti gli ordini siano presenti con questa query. il numero dell'ordine web è il numero da 1 ... n.
Come posso scrivere una query per trovare gli ordini mancanti senza unirmi a una tabella temporanea / diversa?
Soluzione
È possibile unire la tabella su se stessa per rilevare le righe che non hanno una riga precedente:
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
Questo rileverebbe lacune nella sequenza 1 ... n, ma non rileverebbe duplicati.
Altri suggerimenti
Vorrei fare una tabella ausiliaria di " tutti gli interi da 1 a n " (vedi http://www.sql-server-helper.com/ funzioni / integer-table.aspx per alcuni modi per farlo con una funzione di SQL Server, ma dato che è qualcosa di cui avrai bisogno più volte, lo trasformerei comunque in una vera tabella, e con qualsiasi motore SQL è facile farlo, solo una volta) quindi usa una query nidificata, SELEZIONA valore DA numeri interi DOVE valore NON IN (SELEZIONA webordernumber DA ordini)
& amp; c. Vedi anche http://www.sqlmag.com/Article/ArticleID/99797/ sql_server_99797.html per un problema simile al tuo, "rilevamento di spazi vuoti in una sequenza di numeri".
Se hai la funzione rank () ma non la funzione lag () (in altre parole, SQL Server), puoi usarla (suggerita da http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-programming / 10594 / Return-gap-in-a-sequenza ):
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
... oppure, per includere i "limiti esterni":
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)
Se il tuo database supporta funzioni analitiche, puoi utilizzare una query simile a:
select prev+1, curr-1 from
( select webordernumber curr,
coalesce (lag(webordernumber) over (order by webordernumber), 0) prev
from orders
)
where prev != curr-1;
L'output mostrerà le lacune, ad esempio
prev+1 curr-1
------ ------
3 7
significherebbe che mancano i numeri da 3 a 7 inclusi.