Вопрос по sql-server, sql-server-2000, sql, tsql – Вставка n записей с помощью T-SQL

13

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

И я видел отличное решение для этого:

<code>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
</code>

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

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

Ваш Ответ

7   ответов
3

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 строки

0

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
но мне нужно добавить n строк ... это может быть 2, это может быть 2000! Это может сработать при построении динамического запроса, все еще используя цикл while, а затем выполнить вставку в конце, но в любом случае он не будет работать в UDF. David Aleu
Пожалуйста, не цитируйте PinalDave ...
3

который я использую и который лучше всего подходит для моих целей и использования 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 @[email protected]+1
end
2

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

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

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

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

В этом случае выseverely ограничены в том, что вы можете сделать, и почти ни одно из предложенных здесь решений не будет работать. Cade Roux - это, вероятно, ваш лучший выбор.
извините, забыл упомянуть, что я в SQL 2000 David Aleu
17

вы можете использовать рекурсивный 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)

*/
Я думаю, что этот подход должен быть ограничен относительно небольшими наборами результатов, такими как 1000 или меньше. Рекурсивные операции начинают становиться заметно дороже даже для 100 000 результатов. Тем не менее, это все еще должно быть самая приятная вещь здесь.
Несмотря на отрицательную производительность рекурсивного CTE, если вы используете это для генерации строк для вставки, это позволит вам выполнить вставку на основе набора. Использование вышеупомянутого для вставки на основе набора, вероятно, будет намного быстрее, чем вставка одной записи за раз в цикле.
11

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
это тот подход, который я использую и который лучше всего подходит для моих целей и использования SQL 2000. Поскольку в моем случае это внутри UDF, я не могу использовать ## или # временные таблицы, поэтому я использую переменную таблицы, как показано в моем ответе David Aleu

Похожие вопросы