Tsql 运行insert语句x次

Tsql 运行insert语句x次,tsql,Tsql,我有两张桌子。一个表A有n行数据,另一个表B为空。我想在表B中插入n行,表A中每行插入一行。表B中有来自表A的两个字段,包括来自表A的外键 最后,我希望B中的每一行对应A中的每一行。为此,我使用了: INSERT INTO B(Col1 ,Col2 ,Col3 ,Col4 ,Col5 ); SELECT 100 ,25 ,'ABC'

我有两张桌子。一个表A有n行数据,另一个表B为空。我想在表B中插入n行,表A中每行插入一行。表B中有来自表A的两个字段,包括来自表A的外键

最后,我希望B中的每一行对应A中的每一行。为此,我使用了:

INSERT INTO B(Col1
             ,Col2
             ,Col3
             ,Col4
             ,Col5
             );
SELECT 100
      ,25 
      ,'ABC'
      ,1
      ,A.ID
FROM Auctions A
现在,我把这段代码放在一个存储过程中,这个SP接受一个名为NumInserts的int参数

我想插入n*NumInserts行。所以,如果n是10,NumInserts是5,我想运行这个代码5*10 50次

换句话说,对于表A中的每一行,我想在表B中插入5行。我该如何做

 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或更早版本,请将集合@N-=1'替换为集合@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) 

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

我更喜欢在可能的时候避免循环,这样我就不必在存储过程中维护一些容易破坏且有点难看的循环结构

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
您可以使用数字表、交叉应用语句和现有的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始终是一个合理的小数字,那么这个解决方案可能有些过分,但是如果您已经有了一张数字表,那么您最好利用它

更新:

这里有一个快速而肮脏的方法来填充0到65535之间的数字表:

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

信用证:

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

用于按指定次数执行一批命令

具体地说,如果您有一个名为Insertitob的存储过程,则可以在Management Studio中运行该过程:

exec InsertAIntoB
GO 10

用NumInserts非常晚的答案替换10,但不需要循环,而且比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
您可以在联接中使用任何表,只要它具有所需的行数。如果您想在insert表中的某个位置获得副本号,还可以将1[BUNK]更改为按对象id[copyno]排序的行号

希望这能为以后的工作节省一些时间…

试试这个:

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_值,其中type='P'只是一个内置的SQL Server数字表,从0到2047
我会建立一个数字表,从1到一个大的上限1000000或其他数字。然后您可以交叉应用拍卖到数字表,其中数字是好的。我想我下次遇到这个问题时可能会用这个。我打赌也有一种快速而简单的方法来填充数字表。@SachinKainth:我用一种快速而肮脏的方法更新了我的答案,得到了一个小数字表。我投了反对票。我不同意表格中包含日期、数字等内容。有一次我甚至看到一个表格只有两行,对和错。如果要避免循环,请使用CTE,而不是使用表存储数字。为什么要避免循环呢不管你做什么,电脑一定在某处循环。唯一的区别是在什么抽象层次上循环是机械化的@查尔斯布雷塔纳:我同意在某个地方有一个循环;我的论点是:当我可以在已经存在的查询中添加一些额外的指令时,为什么还要费心维护丑陋的循环代码呢?@Cory,我想每个都有自己的指令。从我的角度来看,你创建数字表的代码是不吸引人的。。。将其与CTE进行比较,CTE使用numsnum创建相同的数字>>>作为Select@N Union All Select num-1 From nums Where num>1A nick hack-事实上,我将其用于快速而肮脏的场景。出于某种原因,GO@NumInserts不起作用-我想知道转义有什么帮助。@SachinKainth实际上我认为它不适用于变量。这是因为GO不是真正的T-SQL,而是SQLServerManagementStudio理解的某种宏。