Nuestro experto residente en bases de datos nos dice que las tablas de números son invaluables . No entiendo bien por qué. Aquí hay una tabla de números:
USE Model
GO
CREATE TABLE Numbers
(
Number INT NOT NULL,
CONSTRAINT PK_Numbers
PRIMARY KEY CLUSTERED (Number)
WITH FILLFACTOR = 100
)
INSERT INTO Numbers
SELECT
(a.Number * 256) + b.Number AS Number
FROM
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) a (Number),
(
SELECT number
FROM master..spt_values
WHERE
type = 'P'
AND number <= 255
) b (Number)
GO
Según la publicación del blog, la justificación dada es
Las tablas de números son realmente invaluables. Los uso todo el tiempo para la manipulación de cadenas, simular funciones de ventana, llenar tablas de prueba con muchos datos, eliminar la lógica del cursor y muchas otras tareas que serían increíblemente difíciles sin ellas.
Pero no entiendo exactamente cuáles son esos usos, ¿puede proporcionar algunos ejemplos convincentes y específicos de dónde una "tabla de números" le ahorra una tonelada de trabajo en SQL Server, y por qué deberíamos tenerlos?
sql-server
Jeff Atwood
fuente
fuente
Respuestas:
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:
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:
Ahora hagamos el 'bucle for':
El resultado es:
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
fuente
He encontrado una tabla de números bastante útil en una variedad de situaciones.
¿ Por qué debería considerar usar una tabla de números auxiliares? , escrito en 2004, muestro algunos ejemplos:
Con los malos hábitos para patear: usando bucles para poblar tablas grandes , muestro cómo se puede usar una tabla de números para hacer un trabajo corto de insertar muchas filas (en oposición al enfoque instintivo de usar un bucle while).
En Procesar una lista de enteros: mi enfoque y más sobre la división de listas: delimitadores personalizados, prevención de duplicados y mantenimiento del orden , muestro cómo usar una tabla de números para dividir una cadena (por ejemplo, un conjunto de valores separados por comas) y proporcionar rendimiento comparaciones entre este y otros métodos. Más información sobre división y otro manejo de cadenas:
Y en la Tabla de Números de SQL Server, Explicada - Parte 1 , doy algunos antecedentes sobre el concepto y tengo futuras publicaciones en la tienda para detallar aplicaciones específicas.
Hay muchos otros usos, esos son solo algunos que me han destacado lo suficiente como para escribir sobre ellos.
Y como @gbn, tengo algunas respuestas sobre el desbordamiento de pila y en este sitio que también usan una tabla de números.
Finalmente, tengo una serie de publicaciones de blog sobre la generación de conjuntos sin bucles, que en parte muestran la ventaja de rendimiento de usar una tabla de números en comparación con la mayoría de los otros métodos (aparte del peculiar atípico de Remus):
fuente
Aquí hay un gran ejemplo que usé recientemente de Adam Machanic:
Utilicé algo más similar con a
CTE
para encontrar una instancia específica de subcadena (es decir, "Buscar la tercera tubería en esta cadena") para trabajar con datos delimitados correlacionados:Si no tiene una tabla de números, la alternativa es usar un ciclo de algún tipo. Básicamente, una tabla de números le permite realizar iteraciones basadas en conjuntos, sin cursores ni bucles.
fuente
Usaría una tabla de números cada vez que necesite un equivalente SQL de Enumerable.Range. Por ejemplo, acabo de usarlo en una respuesta en este sitio: calcular el número de permutaciones
fuente