【问题标题】:SQL while loop with scalar variables带有标量变量的 SQL while 循环
【发布时间】:2019-05-17 19:11:26
【问题描述】:

我之前多次运行过这种类型的代码,但在另一个组织的另一个环境中运行,并且 SQL Server 上的版本不完全相同。下面的示例代码已简化,但它可以作为我的问题的示例。

在此示例中,我尝试在几年内进行循环(“ar”变量),并为每年在另一个数据库中创建一个新表,而不是原始表的保存位置。原始表包括所有年份。原表中的“ar”变量是一个int。

我的代码如下所示:

declare @Ar int = 2007
declare @ArVC varchar(4)=''
declare @CreateTable varchar(MAX)=''
declare @DB varchar(MAX)='MIRK3utv'

while @Ar <= 2015
begin

set @ArVC = cast(@Ar as varchar)

set @CreateTable = '
    select *
    into ' + @DB + 'dbo.Tab_' + @ArVC + '
    from DBorg.dbo.OrgTab
    where ar = ' + @ArVC

exec @CreateTable

set @Ar = @Ar + 1

end

这给了我一个错误,上面写着:

消息 203,第 16 级,状态 2,第 34 行 名字 ' 选择 * 进入 MIRK3utv.dbo.Tab_2007 来自 DBorg.dbo.OrgTab 其中 ar = 2007' 不是有效标识符。

我在这里缺少什么?我已经在网上和这个论坛上搜索了答案,但在这种情况下我似乎找不到适合我的解决方案。

【问题讨论】:

  • 你应该使用QUOTENAME(@DB)QUOTENAME('Tab'+@ArVC)来避免SQL注入。
  • @CreateTable 应该是NVARCHAR(MAX) 以支持Unicode 命名对象
  • 而且@DB 也应该是Unicode,最好是sysname 类型,因为它确实代表系统对象(数据库名称)
  • 最后,将@ArVC 作为参数传递给sp_executesql 以避免在执行SQL 中嵌入值的问题:set @CreateTable = N'select * from ... where ar = @ArVCexec sp_executesql @createSQL, N'@ArVC varchar(4)', @ArVC

标签: sql sql-server sql-server-2014 declare scalar


【解决方案1】:

要执行动态 SQL,您有两种选择:使用 EXEC(@SQL) 或使用 EXEC sp_ExecuteSql @Sql
请注意,第一个选项包括括号 - 如果没有括号,SQL Server 会假定您正在尝试执行存储过程 - 这就是您遇到错误的原因。

您在问题中发布的代码也缺少将数据库名称与架构名称分开的点,但它确实出现在错误消息中,因此我认为这只是问题本身的错字。

你可以像这样运行这段代码:

declare @Ar int = 2007
declare @ArVC varchar(4)=''
declare @CreateTable varchar(MAX)=''
declare @DB varchar(MAX)='MIRK3utv'

while @Ar <= 2015
begin

set @ArVC = cast(@Ar as varchar)

set @CreateTable = '
    select *
    into ' + @DB + '.dbo.Tab_' + @ArVC + ' -- added the missing dot
    from DBorg.dbo.OrgTab
    where ar = ' + @ArVC

exec(@CreateTable) -- Note the parenthesis!

set @Ar = @Ar + 1

【讨论】:

  • 迄今为止唯一真正解释为什么 OP 的代码会产生错误的回复。
  • 非常感谢!是的,当我输入问题时,点是我的错误。我的代码处于某种“看起来”的环境中,所以我无法复制它。括号起到了作用。它们在我的其他代码中,所以我一定是在那里失去了我的大脑,而且在我数小时的错误检查中我从未注意到它,这真是太神奇了。 :) 再次感谢。
  • 很高兴为您提供帮助 :-)
【解决方案2】:

我会这样写:

declare @Ar int = 2007;
declare @CreateTable nvarchar(MAX) = N''
declare @DB nvarchar(MAX)=  N'MIRK3utv'

while @Ar <= 2015
begin

    set @CreateTable = N'
select *
into ' + @DB + '.dbo.Tab_@Ar
from DBorg.dbo.OrgTab
where ar = @Ar';

    set @CreateTable = replace(@CreateTable, @Ar);

    exec sp_executesql @CreateTable

    set @Ar = @Ar + 1
end;

【讨论】:

    【解决方案3】:

    怎么样

    DECLARE @SQL NVARCHAR(MAX) = '';
    
    WITH Years AS
    (
      SELECT 2007 Ar
      UNION ALL
      SELECT Ar + 1
      FROM Years
      WHERE Ar < 2015
    )
    SELECT @SQL = @SQL + 
                  N'SELECT * INTO MIRK3utv.dbo.Tab_' + 
                  CAST(Ar AS VARCHAR) + 
                  ' FROM DBorg.dbo.OrgTab WHERE Ar = ''' + 
                  CAST(Ar AS VARCHAR) + '''; '
    FROM Years;
    
    SELECT @SQL;
    --EXECUTE sp_executesql @SQL;
    

    我不明白你为什么需要在这里使用循环

    See the results here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-10
      • 2022-07-07
      • 1970-01-01
      • 2017-12-09
      • 2023-03-10
      • 2014-02-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多