2009-06-24 2 views
13

Je veux ajouter un nombre variable d'enregistrements dans une table (jours)Numéro d'insertion de n d'enregistrements avec T-SQL

Et je l'ai vu une solution propre pour cela:

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 

Mais malheureusement, cela ne fonctionne pas dans un UDF (parce que le #temp et le SET ROWCOUNT). Une idée de comment cela pourrait-il être réalisé? En ce moment, je le fais avec une variable WHILE et une variable table, mais en termes de performance ce n'est pas une bonne solution.

Répondre

3

c'est l'approche que je J'utilise et fonctionne mieux pour mes buts et en utilisant SQL 2000. Parce que dans mon cas est dans un UDF, je ne peux pas utiliser ## ou # tables temporaires, donc j'utilise une variable de table. que je fais:

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

Vous pouvez faire ce que PinalDave suggère:

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

mais j'ai besoin d'ajouter n lignes ... ça pourrait être 2 ça pourrait être 2000! Cela pourrait fonctionner de construire une requête dynamique encore en utilisant la boucle while et puis faire l'insertion à la fin, mais cela ne fonctionnerait pas dans un UDF anywyay. –

+2

Ne citez pas PinalDave ... – gbn

2

vous pouvez utiliser une jointure croisée

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

Vous pouvez utiliser une instruction while pour 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

c'est l'approche que j'utilise et qui fonctionne le mieux pour mes buts et en utilisant SQL 2000. Parce que dans mon cas c'est dans un UDF, je ne peux pas utiliser ## ou # tables temporaires donc j'utilise une variable de table comme indiqué dans ma réponse –

16

Si vous En utilisant SQL 2005 ou plus récent, vous pouvez utiliser un CTE récursif pour obtenir une liste de dates ou de nombres ...

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

Je pense que cette approche devrait être limitée à des ensembles de résultats relativement petits comme 1000 ou moins. Les opérations récursives commencent à devenir visiblement chères même pour 100 000 résultats. Cependant, il doit toujours être la chose la plus propre ici. – SurroundedByFish

+0

Malgré les performances négatives du CTE récursif, si vous l'utilisez pour générer des lignes pour un insert, cela vous permettra de faire un insert basé sur un ensemble. L'utilisation de ce qui précède pour un insert basé sur un ensemble sera probablement beaucoup plus rapide que l'insertion d'un seul enregistrement à la fois dans une boucle. – AaronLS

2

Lorsque vous avez une table de numéros pré-construits, il suffit d'utiliser que:

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

Il y a un certain nombre de techniques pour la construction de la table des numéros en premier lieu (en utilisant des techniques ici), mais Une fois construit et indexé, vous ne le construisez plus.

+0

La plupart des gens, en particulier des milieux de codeurs, riraient à l'idée d'avoir une table qui est juste remplie d'un million ou plus de numéros séquentiels. Cependant, je pense que c'est en fait la meilleure solution ici. C'est-à-dire que c'est la solution qui rompt le moins l'intention des opérations basées sur les ensembles et n'est pas un hack. Les codeurs pensent à l'itération et à la récursivité, mais ils ont du mal à comprendre les opérations basées sur des ensembles. La table des "nombres" va occuper un espace constant et relativement petit et retourner des résultats extrêmement rapides même pour des ensembles de résultats massifs. Mais bon, ce n'est pas sexy. – SurroundedByFish

+0

Que vous le construisiez à la volée et que vous le construisiez, c'est toujours une table de nombres (même si elle est déguisée en une série de dates). –

0

Que diriez-vous:

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 vous ne voulez pas zéro indexé, retirez le "- 1"

nécessite au moins SQL Server 2005.

+0

désolé, j'ai oublié de mentionner que je suis sur SQL 2000 –

+0

Dans ce cas, vous êtes * sévèrement * limité dans ce que vous pouvez faire, et presque aucune des solutions suggérées ici ne fonctionnera. Cade Roux est probablement votre meilleur pari. – GalacticCowboy

3

Dans l'ensemble beaucoup plus rapide de doubler le nombre de lignes à chaque itération

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; 

Je délibérément ne pas SET NOCOUNT ON, de sorte que vous voyez comment il insère 1,2 , 4,8 rangées