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"。最终肌肉记忆开始了:)
我正在与一位客户合作,他以某种方式将小写商品编号加载到一系列 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"。最终肌肉记忆开始了:)