T-SQL Cursor用于更新多个表中的多个列

时间:2015-09-10 03:10:16

标签: sql-server tsql cursor sql-update

我正在与一位以某种方式将小写项目编号加载到一系列SQL表中的客户合作。在这个特定的应用程序中这不应该是可能的并且引起各种各样的问题。我开始一次一个地将项目更新为大写版本,但很快意识到这将需要永远。所以我做了不可思议的事情并试图用光标来帮助我,但是我一直在绊倒让我困惑的错误。这是我的代码:

declare @tablename varchar(10)

declare upper_case cursor for 
    SELECT sys.objects.NAME
    FROM sys.columns
    INNER JOIN sys.objects ON sys.columns.object_id = sys.objects.object_id
    WHERE sys.columns.NAME = 'item'
      AND sys.objects.type = 'U'

OPEN upper_case
FETCH NEXT FROM upper_case into @tablename

UPDATE @tablename
SET item = upper(item)

CLOSE upper_case
DEALLOCATE upper_case

这是错误:

  

Msg 1087,Level 16,State 1,Line 13
  必须声明表变量“@tablename”。

我没有使用@tablename作为表变量,我试图将它用作标量变量,但我想,哎呀,我会咬人。所以我将其切换为表变量:

declare @tablename table (tablename varchar(10))

然后我收到了这个错误:

  

Msg 137,Level 16,State 1,Line 5
  必须声明标量变量“@tablename”。

我错过了什么?我不允许在UPDATE语句中使用变量吗?我知道每个UPDATE只能更新一个表,但我认为通过使用游标,我实际上发出了多个更新,每个更新只更新一个表。我误解了吗?

这是有效的结果。我不敢相信我是第一个想要这样做的人,我怀疑我会是最后一个:

DECLARE @tablename varchar(10)
DECLARE @sql nvarchar(max)

declare upper_case cursor for 
    SELECT sys.objects.NAME
    FROM sys.columns
    INNER JOIN sys.objects ON sys.columns.object_id = sys.objects.object_id
    WHERE sys.columns.NAME = 'item'
      AND sys.objects.type = 'U'

OPEN upper_case
FETCH upper_case into @tablename

WHILE @@FETCH_STATUS = 0
BEGIN
    SET @sql = 'UPDATE [' + @tablename + '] SET item = upper(item)'
    EXEC(@sql)

    FETCH upper_case into @tablename
END

CLOSE upper_case
DEALLOCATE upper_case

2 个答案:

答案 0 :(得分:3)

UPDATE您不能像尝试一样将表名作为变量传递:

UPDATE @tablename
SET item = upper(item);
  

消息1087,级别16,状态1,行13必须声明表变量   “@tablename”

但是UPDATE可以使用表变量DECLARE @t TABLE = ...(不是你的情况)。

要使用它,您需要使用Dynamic-SQL,如:

EXEC('UPDATE [' + @tablename + '] SET item = UPPER(item)');

答案 1 :(得分:2)

正如lad2025指出的那样,您需要使用动态SQL技术来完成您要做的事情。另外两点:

首先,您只更新光标返回的第一个结果。您需要使用while循环来迭代光标结果,如下所示:

....
FETCH NEXT FROM upper_case into @tablename

WHILE @@FETCH_STATUS = 0
BEGIN
    <do dynamic update>

    FETCH NEXT FROM upper_case into @tablename
END
<close & deallocate>

其次,我真的鼓励使用INFORMATION_SCHEMA视图而不是直接查询系统表。出于您的目的,它们提供了足够多的信息,并且在SQL版本之间更具可读性和稳定性。

INFORMATION_SCHEMA中的系统元数据是SQL-92标准。它在MS-SQL版本和其他符合ANSI-SQL标准的引擎中保持稳定。另见:INFORMATION_SCHEMA vs sysobjects。编写快速脚本的主要缺点是您必须键入“information_schema”而不是“sys”。最终肌肉记忆开始了:))