Ho visto molti usi quando è necessario proiettare "dati mancanti". Per esempio. hai una serie temporale (un registro di accesso per esempio) e vuoi mostrare il numero di hit al giorno negli ultimi 30 giorni (pensa alla dashboard di analisi). Se lo fai select count(...) from ... group by day
otterrai il conteggio per ogni giorno, ma il risultato avrà solo una riga per ogni giorno in cui hai avuto almeno un accesso. D'altra parte, se prima proietti una tabella di giorni dalla tabella dei numeri ( select dateadd(day, -number, today) as day from numbers
) e poi lasci unirti ai conteggi (o applicare esterno, qualunque cosa tu voglia), otterrai un risultato che ha 0 per il conteggio per i giorni in cui non aveva accesso. Questo è solo un esempio. Naturalmente, si potrebbe sostenere che il livello di presentazione della dashboard potrebbe gestire i giorni mancanti e invece mostrare solo uno 0, ma alcuni strumenti (ad esempio SSRS) non saranno semplicemente in grado di gestirlo.
Altri esempi che ho visto hanno usato trucchi di serie temporali simili (data / ora +/- numero) per eseguire tutti i tipi di calcoli delle finestre. In generale, ogni volta che in un linguaggio imperativo useresti un ciclo for con un numero ben noto di iterazioni, la natura dichiarativa e impostata di SQL può usare un trucco basato su una tabella numerica.
A proposito, sento il bisogno di sottolineare il fatto che anche se usando una tabella dei numeri sembra un'esecuzione procedurale imperativa, non cadere nell'errore di presumere che sia imperativo. Lasciami fare un esempio:
int x;
for (int i=0;i<1000000;++i)
x = i;
printf("%d",x);
Questo programma produrrà 999999, che è praticamente garantito.
Proviamo lo stesso in SQL Server, usando una tabella numerica. Innanzitutto crea una tabella di 1.000.000 di numeri:
create table numbers (number int not null primary key);
go
declare @i int = 0
, @j int = 0;
set nocount on;
begin transaction
while @i < 1000
begin
set @j = 0;
while @j < 1000
begin
insert into numbers (number)
values (@j*1000+@i);
set @j += 1;
end
commit;
raiserror (N'Inserted %d*1000', 0, 0, @i)
begin transaction;
set @i += 1;
end
commit
go
Ora facciamo il 'for loop':
declare @x int;
select @x = number
from numbers with(nolock);
select @x as [@x];
Il risultato è:
@x
-----------
88698
Se ora stai vivendo un momento WTF (dopo tutto number
è la chiave primaria in cluster!), Il trucco si chiama scansione dell'ordine di allocazione e non ho inserito @j*1000+@i
per caso ... Potresti anche avventurarti in un'ipotesi e dire che il risultato è perché parallelismo e che a volte può essere la risposta corretta.
Ci sono molti troll sotto questo bridge e ne ho menzionati alcuni in On SQL Server, il cortocircuito dell'operatore booleano e le funzioni T-SQL non implicano un certo ordine di esecuzione