【问题标题】:Insert values into dynamically created table in the same stored procedure在同一存储过程中将值插入动态创建的表中
【发布时间】:2015-03-09 13:26:05
【问题描述】:

我的任务是:创建一个表,并在同一个存储过程中向表中插入 n 个值。

CREATE PROCEDURE PROC
    @tableName nvarchar(30),
    @nRows          int
AS
BEGIN
    IF EXISTS (SELECT * FROM sys.objects 
               WHERE object_id = OBJECT_ID(@tableName) 
                 AND type in (N'U'))
        DROP TABLE [dbo].[@tableName ]

    DECLARE @SQLString NVARCHAR(MAX)

    SET @SQLString = 'CREATE TABLE ' + @tableName +
                     '(
                          [ID] [int] IDENTITY(1,1) NOT NULL,
                          [col1] [int] NOT NULL
                      ); GO';

    EXEC (@SQLString);

    DECLARE @i int = 1;

    WHILE (@i <= @nRows)
    BEGIN
        SET @i = @i + 1;

        INSERT INTO @tableName values (@i);
    END
END

我知道问题是表在提交之前不存在;这就是为什么我不能插入。但是如何重写它才能完成我的任务?

【问题讨论】:

  • 这里有几个问题。首先,您需要使用 Quotename 包装您的表变量,以帮助防止 sql 注入,或者如果该值包含空格或其他需要使用方括号的字符。然后你需要使用数字或计数表而不是循环插入一堆整数。插入也必须使用动态 sql 完成,您不能像使用变量名那样进行插入。

标签: sql sql-server stored-procedures sql-insert


【解决方案1】:

插入应该是动态的。使用sp_executesql:

....

EXEC (@SQLString);

DECLARE @params NVARCHAR(MAX) = '@i INT'
SET @SQLString = 'INSERT INTO ' + @tableName + ' VALUES(@i)'

DECLARE @i INT = 1;
WHILE ( @i <= @nRows )
    BEGIN
        SET @i = @i + 1;
        EXEC sp_executesql @SQLString, @params, @i;
    END

没有循环执行的版本:

....

EXEC (@SQLString);

SET @SQLString = 'INSERT INTO ' + @tableName + ' VALUES'

DECLARE @i INT = 1;
WHILE ( @i <= @nRows )
    BEGIN
        SET @SQLString = @SQLString + '(' + CAST(@i AS NVARCHAR(MAX)) + '),'
        SET @i = @i + 1;
    END

EXEC(SUBSTRING(@SQLString, 1, LEN(@SQLString) - 1))

带 Tally 的版本:

....

EXEC (@SQLString);

SET @SQLString = '
;WITH cte AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT (1))) AS RN FROM 
           (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) d(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) e(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) f(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) g(ID)
CROSS JOIN (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) h(ID)
)
INSERT INTO ' + @tableName + '
SELECT RN FROM cte WHERE RN <= ' + CAST(@nRows AS NVARCHAR(MAX))

EXEC(@SQLString)

【讨论】:

  • 创建一个包含 1000 个插入语句的字符串然后执行它可能会更好。
  • 如果你在这里使用计数/数字表而不是循环会更好。
  • 我怀疑底层表结构会更复杂,并且计数不会有帮助。
  • 在插入连续整数时,计数怎么会无济于事?
  • 我怀疑提供的示例已简化为顺序集。
【解决方案2】:

当您在查询中使用变量时,您应该将总查询分配给另一个变量,然后将其执行为.....

DECLARE @sqlstring2 NVARCHAR(MAX) = 'INSERT INTO ' + @tableName + ' VALUES(@i);'
 exec(@sqlstring2)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多