运行insert语句x次

时间:2012-11-20 15:33:43

标签: tsql

我有两张桌子。一个表A有n行数据,另一个表B为空。我希望将insert n行放入表B中,为表A中的每一行添加1行。表B中包含表A中的几个字段,包括表A中的外键。

最后,我想在B中为A中的每一行添加一行。为此,我使用了:

INSERT INTO B(Col1
             ,Col2
             ,Col3
             ,Col4
             ,Col5
             );
SELECT 100
      ,25 
      ,'ABC'
      ,1
      ,A.ID
FROM Auctions A

现在,我已将此代码放在存储过程中,此SP采用名为int的{​​{1}}参数。

我想插入NumInserts行。因此,如果n为10且NumInserts为5,我想运行此代码5 * 10(50)次。

换句话说,对于n * NumInserts中的每一行,我想table A中的insert 5行。我该怎么做?

6 个答案:

答案 0 :(得分:14)

create procedure insert_into_b
    @numInserts int
as
begin
    while @numInserts > 0
    begin
        insert into b (id)
        select id from a
        set @numInserts = @numInserts - 1
    end
end

exec insert_into_b 2

答案 1 :(得分:7)

我希望尽可能避免循环,这样我就不必在存储过程中维护一些容易破解且有些丑陋的循环结构。

您可以使用Numbers表格,CROSS APPLY语句和现有的INSERT语句轻松完成此操作。

鉴于你的数字表看起来像这样:

Number
======
0
1
2
...

您的SQL语句变为:

INSERT INTO B 
(
    [Col1]
    ,[Col2]
    ,[Col3]
    ,[Col4]
    ,[Col5]
)
SELECT 
    100 
    ,25
    ,'ABC'
    ,1
    ,a.ID
FROM 
    Auctions a
CROSS APPLY
    Numbers n
WHERE
    n.Number BETWEEN 1 AND @NumInserts

如果使用得当,数字表会很有用。如果你不熟悉它们,这里有一些资源和一些优点/缺点:

如果@NumInserts总是一个相当小的数字,也许这个解决方案有点过分,但如果你已经有一张Numbers表,你可以利用它!

<强>更新

这是一个快速而简单的方法,可以将数字表从0填充到65,535:

CREATE TABLE Numbers
(
    Number INT NOT NULL,
    CONSTRAINT PK_Numbers 
        PRIMARY KEY CLUSTERED (Number)
        WITH FILLFACTOR = 100
)
GO

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

信用: http://dataeducation.com/you-require-a-numbers-table/

答案 2 :(得分:5)

这是一个黑客,我不建议在生产或大量数据中使用它。但是,在开发快速和肮脏的场景中,我发现它通常很有用:

使用GO \[count\]执行指定次数的一批命令。

具体而言,如果您有一个名为InsertAIntoB的存储过程,则可以在Management Studio中运行它:

exec InsertAIntoB
GO 10

(用任何NumInserts替换10

答案 3 :(得分:1)

 Create procedure DoitNTimes 
 @N integer = 1
 As
 Set NoCount On

    While @N > 0 Begin
       Insert B (Col1, Col2, Col3, Col4, Col5)
       Select 100, 25, 'ABC', 1, A.ID
       From Auctions A
       -- -----------------------------------
       Set @N -= 1
    End

如果使用SQL Server 2005或更早版本替换Set @N -= 1' with设置@N = @ N-1`

如果你真的想避免使用T-SQL变量循环,那么使用CTE,而不是基于磁盘的表:

 Create procedure DoitNTimes 
 @N integer = 1
 As
 Set NoCount On

     With nums(num) As
       (Select @N Union All
        Select num - 1
        From nums
        Where num > 1)
     Insert B (Col1, Col2, Col3, Col4, Col5)
     Select 100, 25, 'ABC', 1, A.ID
     From Auctions A Full Join nums
     Option(MaxRecursion 10000) 

但当然,这仍然是循环,就像这个问题的任何解决方案一样。

答案 4 :(得分:0)

答案非常晚,但没有必要循环,这比Corey的好答案简单一点;

DECLARE @n int = 10;
INSERT INTO B(Col1,Col2,Col3,Col4,Col5);
SELECT 100,25,'ABC',1,A.ID
FROM Auctions A
JOIN (SELECT TOP(@n) 1 [junk] FROM sys.all_objects) as copies ON 1 = 1

只要具有您需要的行数,您就可以使用连接中的任何表。您还可以将“1 [垃圾]”更改为“ROW_NUMBER()OVER(ORDER BY object_id)[copyno]”如果您想在插入表格中的某处复制数字。

希望这会为某人节省一些工作......

答案 5 :(得分:0)

尝试一下:

DECLARE @NumInserts SMALLINT = 3

INSERT INTO B (Col1, Col2, Col3, Col4, Col5)
    SELECT 100, 25, 'ABC', 1, A.ID
    FROM Auctions A
        JOIN master.dbo.spt_values numbers ON numbers.number < @NumInserts
    WHERE numbers.[type] = 'P'
  • 注意:仅在@NumInserts小于或等于2048时有效
  • master.dbo.spt_values WHERE type = 'P'只是一个内置的SQL Server数字表,范围是0到2047