14

我有两张桌子。一张表A有 n 行数据,另一张表B为空。我想将insertn 行放入表中B,表中的每一行 1 行A。TableB将有几个来自 table 的字段A,包括来自 table 的外键A

最后,我希望BA. 为此,我使用了:

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

现在,我把这段代码放在一个存储过程中,这个 SP 接受一个int名为NumInserts.

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

换句话说,table A我想要insert5 行中的每一行table B。我该怎么做?

4

6 回答 6

18
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
于 2012-11-20T15:42:37.520 回答
10

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

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/

于 2012-11-20T15:47:32.903 回答
10

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

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

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

exec InsertAIntoB
GO 10

10用任何 NumInserts 替换)

于 2012-11-20T15:55:19.950 回答
2
 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' withSet @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) 

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

于 2012-11-20T15:39:35.237 回答
1

很晚的答案,但不需要循环,它比 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 [junk]”更改为“ROW_NUMBER() OVER(ORDER BY object_id) [copyno]”。

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

于 2018-03-08T19:10:05.007 回答
0

试试这个(在 SQL 服务器数据库上):

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'只是一个从 0 到 2047 的内置 SQL Server 数字表
于 2020-10-20T00:25:22.630 回答