He visto muchos usos cuando necesitas proyectar 'datos faltantes'. P.ej. tiene una serie temporal (un registro de acceso, por ejemplo) y desea mostrar la cantidad de visitas por día durante los últimos 30 días (piense en el panel de análisis). Si lo haces select count(...) from ... group by day
, obtendrás el recuento de cada día, pero el resultado solo tendrá una fila por cada día en que realmente tengas al menos un acceso. Por otro lado, si primero proyecta una tabla de días de su tabla de números ( select dateadd(day, -number, today) as day from numbers
) y luego se une a los recuentos (o aplicación externa, lo que desee), obtendrá un resultado que tiene 0 para contar los días que No tenía acceso. Esto es sólo un ejemplo. Por supuesto, uno puede argumentar que la capa de presentación de su tablero podría manejar los días que faltan y simplemente mostrar un 0, pero algunas herramientas (por ejemplo, SSRS) simplemente no podrán manejar esto.
Otros ejemplos que he visto utilizan trucos de series de tiempo similares (fecha / hora +/- número) para hacer todo tipo de cálculos de ventanas. En general, siempre que en un lenguaje imperativo use un bucle for con un número conocido de iteraciones, la naturaleza declarativa y establecida de SQL puede usar un truco basado en una tabla de números.
Por cierto, siento la necesidad de mencionar el hecho de que, aunque usar una tabla de números se siente como una ejecución procesal imperativa, no caiga en la falacia de suponer que es imprescindible. Déjame dar un ejemplo:
int x;
for (int i=0;i<1000000;++i)
x = i;
printf("%d",x);
Este programa generará 999999, eso está prácticamente garantizado.
Probemos lo mismo en SQL Server, usando una tabla de números. Primero cree una tabla de 1,000,000 de números:
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
Ahora hagamos el 'bucle for':
declare @x int;
select @x = number
from numbers with(nolock);
select @x as [@x];
El resultado es:
@x
-----------
88698
Si ahora está teniendo un momento WTF (¡después de todo number
es la clave primaria agrupada!), El truco se llama exploración de orden de asignación y no lo inserté @j*1000+@i
por accidente ... También podría aventurarse a adivinar y decir que el resultado es porque paralelismo y que a veces puede ser la respuesta correcta.
Hay muchos trolls bajo este puente y mencioné algunos en las funciones de cortocircuito del operador booleano en el servidor SQL y las funciones T-SQL no implican un cierto orden de ejecución