T-SQL 游标更新多个表中的多个列

T-SQL Cursor to update several columns in several tables

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

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
Must declare the table variable "@tablename".

我没有将 @tablename 用作 table 变量,我正在尝试将其用作标量变量,但我想,管它呢,我会坚持下去。所以我将其切换为 table 变量:

declare @tablename table (tablename varchar(10))

然后我得到这个错误:

Msg 137, Level 16, State 1, Line 5
Must declare the scalar variable "@tablename".

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

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

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

UPDATE 你不能像你尝试的那样将 table 名称作为变量传递:

UPDATE @tablename
SET item = upper(item);

Msg 1087, Level 16, State 1, Line 13 Must declare the table variable "@tablename"

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

要按你想要的方式使用它,你需要 Dynamic-SQL 比如:

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

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

首先,您只更新光标 returns 的第一个结果。您需要使用 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"。最终肌肉记忆开始了:)