2009-06-24 9 views
13

Quiero añadir un número variable de registros en una tabla (días)Inserción número n de registros con T-SQL

y he visto una buena solución para esto:

SET @nRecords=DATEDIFF(d,'2009-01-01',getdate()) 
SET ROWCOUNT @nRecords 
INSERT int(identity,0,1) INTO #temp FROM sysobjects a,sysobjects b 
SET ROWCOUNT 0 

Pero lamentablemente eso no funciona en un UDF (porque el #temp y el SET ROWCOUNT). ¿Alguna idea de cómo se podría lograr esto?

Por el momento lo hago con WHILE y una variable de tabla, pero en términos de rendimiento no es una buena solución.

Respuesta

3

este es el enfoque que Estoy usando y funciona mejor para mis propósitos y el uso de SQL 2000. Debido a que en mi caso se encuentra dentro de una UDF, no puedo usar tablas temporales ## o #, así que utilizo una variable de tabla. que estoy haciendo:

DECLARE @tblRows TABLE (pos int identity(0,1), num int) 
DECLARE @numRows int,@i int 


SET @numRows = DATEDIFF(dd,@start,@end) + 1 
SET @i=1 

WHILE @i<@numRows 
begin 
    INSERT @tblRows SELECT TOP 1 1 FROM sysobjects a 

    SET @[email protected]+1 
end 
0

Se podría hacer lo PinalDave sugiere:

INSERT INTO MyTable (FirstCol, SecondCol) 
SELECT 'First' ,1 
UNION ALL 
SELECT 'Second' ,2 
UNION ALL 
SELECT 'Third' ,3 
UNION ALL 
SELECT 'Fourth' ,4 
UNION ALL 
SELECT 'Fifth' ,5 
GO 
+0

pero necesito agregar n filas ... ¡podría ser 2 podría ser 2,000! Eso podría funcionar construyendo una consulta dinámica aún usando el ciclo while y luego hacer la inserción al final, pero no funcionaría en ningún UDF. –

+2

Por favor, no cotice PinalDave ... – gbn

2

se puede utilizar una combinación cruzada

select top 100000 row_number() over(order by t1.number)-- here you can change 100000 to a number you want or a variable 
from master.dbo.spt_values t1 
     cross join master.dbo.spt_values t2 
11

Se puede utilizar una declaración mientras que para los que:

declare @i int 
declare @rows_to_insert int 
set @i = 0 
set @rows_to_insert = 1000 

while @i < @rows_to_insert 
    begin 
    INSERT INTO #temp VALUES (@i) 
    set @i = @i + 1 
    end 
+0

este es el enfoque que estoy usando y funciona mejor para mis propósitos y el uso de SQL 2000. Porque en mi caso está dentro de una UDF, no puedo usar ## o # tablas temporales así que utilizo una variable de tabla como se muestra en mi respuesta –

16

Si' Utilizando SQL 2005 o posterior, puede usar un CTE recursivo para obtener una lista de fechas o números ...

with MyCte AS 
    (select MyCounter = 0 
    UNION ALL 
    SELECT MyCounter + 1 
    FROM  MyCte 
    where MyCounter < DATEDIFF(d,'2009-01-01',getdate())) 
select MyCounter, DATEADD(d, MyCounter, '2009-01-01') 
from MyCte 
option (maxrecursion 0) 


/* output... 
MyCounter MyDate 
----------- ----------------------- 
0   2009-01-01 00:00:00.000 
1   2009-01-02 00:00:00.000 
2   2009-01-03 00:00:00.000 
3   2009-01-04 00:00:00.000 
4   2009-01-05 00:00:00.000 
5   2009-01-06 00:00:00.000 
.... 
170   2009-06-20 00:00:00.000 
171   2009-06-21 00:00:00.000 
172   2009-06-22 00:00:00.000 
173   2009-06-23 00:00:00.000 
174   2009-06-24 00:00:00.000 

(175 row(s) affected) 

*/ 
+3

. Creo que este enfoque debería limitarse a conjuntos de resultados relativamente pequeños, como 1.000 o menos. Las operaciones recursivas comienzan a hacerse visiblemente caras incluso para 100.000 resultados. Sin embargo, todavía tiene que ser lo más útil aquí. – SurroundedByFish

+0

A pesar del rendimiento negativo del CTE recursivo, si está utilizando esto para generar filas para una inserción, esto le permitirá hacer una inserción basada en conjunto. Usar lo anterior para una inserción basada en conjunto probablemente sea mucho más rápido que insertar un solo registro a la vez en un bucle. – AaronLS

2

Cuando se tiene una tabla de números pre-construidos, sólo tiene que utilizar:

SELECT * 
FROM numbers 
WHERE number <= DATEDIFF(d,'2009-01-01',getdate()) 

Hay un gran número de técnicas para la construcción de la tabla de números en el primer lugar (utilizando técnicas aquí), pero una vez que está construido e indexado, no lo compila de nuevo.

+0

La mayoría de las personas, especialmente de fondos de codificador, se reirían de la idea de tener una tabla que acaba de llenar con un millón o más números secuenciales. Sin embargo, creo que esta es realmente la mejor solución aquí. Es decir, es la solución que menos rompe la intención de las operaciones basadas en conjuntos y no es un truco. Los codificadores piensan en la iteración y la recursión, pero tienen problemas para comprender las operaciones basadas en conjuntos. La tabla de "números" ocupará una cantidad constante y relativamente pequeña de espacio y devolverá resultados extremadamente rápidos incluso para conjuntos de resultados masivos. Pero bueno, no es sexy. – SurroundedByFish

+0

Ya sea que lo construyas sobre la marcha y como lo construyas, sigue siendo una tabla de números (incluso si está disfrazada de una serie de fechas). –

0

¿Qué tal:

DECLARE @nRecords INT 

SET @nRecords=DATEDIFF(d,'2009-01-01',getdate()) 

SELECT TOP (@nRecords) 
    ROW_NUMBER() OVER (ORDER BY a.object_id, b.object_id) - 1 
FROM sys.objects a, sys.objects b 

Si no lo quiero en un índice de cero, quitar el "- 1"

requiere al menos SQL Server 2005.

+0

lo siento, me olvidé de mencionar que estoy en SQL 2000 –

+0

En ese caso, está * severamente * limitado en lo que puede hacer, y casi ninguna de las soluciones sugeridas aquí funcionará. Cade Roux's es probablemente tu mejor opción. – GalacticCowboy

3

general mucho más rápido para duplicar la cantidad de filas en cada iteración

CREATE TABLE dbo.Numbers(n INT NOT NULL PRIMARY KEY) 
GO 
DECLARE @i INT; 
SET @i = 1; 
INSERT INTO dbo.Numbers(n) SELECT 1; 
WHILE @i<128000 BEGIN 
    INSERT INTO dbo.Numbers(n) 
    SELECT n + @i FROM dbo.Numbers; 
    SET @i = @i * 2; 
END; 

Deliberadamente no SET NOCOUNT ON, por lo que se ve cómo se inserta 1,2 , 4,8 filas

Cuestiones relacionadas