Вставка n записей с помощью T-SQL - PullRequest
13 голосов
/ 25 июня 2009

Я хочу добавить переменное количество записей в таблице (дней)

И я нашел для этого подходящее решение:

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

Но, к сожалению, это не работает в UDF (потому что #temp и SET ROWCOUNT). Есть идеи, как этого достичь?

В данный момент я делаю это с WHILE и табличной переменной, но с точки зрения производительности это не очень хорошее решение.

Ответы [ 8 ]

17 голосов
/ 25 июня 2009

Если вы используете SQL 2005 или новее, вы можете использовать рекурсивный CTE, чтобы получить список дат или чисел ...

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)

*/
11 голосов
/ 25 июня 2009

Для этого вы можете использовать оператор WHILE:

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
3 голосов
/ 30 июня 2009

В целом гораздо быстрее удваивать количество строк на каждой итерации

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; 

Я сознательно не установил NOCOUNT ON, чтобы вы видели, как он вставляет 1,2,4,8 строки

3 голосов
/ 26 июня 2009

это подход, который я использую и лучше всего подходит для моих целей и использования SQL 2000. Поскольку в моем случае это внутри UDF, я не могу использовать ## или # временные таблицы, поэтому я использую переменную таблицы. Я делаю:

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 @i=@i+1
end
2 голосов
/ 25 июня 2009

Если у вас есть готовая таблица чисел, просто используйте это:

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

Существует множество методов для создания таблицы чисел (с использованием методов здесь), но как только она построена и проиндексирована, вы не создадите ее снова.

2 голосов
/ 25 июня 2009

вы можете использовать кросс-соединение

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
0 голосов
/ 25 июня 2009

Как насчет:

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

Если вы не хотите, чтобы индекс был нулевым, удалите " - 1"

Требуется как минимум SQL Server 2005.

0 голосов
/ 25 июня 2009

Вы можете сделать то, что PinalDave предлагает:

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
...