【发布时间】:2019-11-25 22:04:23
【问题描述】:
我有一张表,其中国家名称定期更改,例如 my_table_US_NA、my_table_CAN_NA、my_table_MEX_NA 等:
create table my_table_US_NA(id int)
insert into my_table_US_NA(id) values (1)
insert into my_table_US_NA(id) values (2)
insert into my_table_US_NA(id) values (3)
insert into my_table_US_NA(id) values (4)
select * from my_table_US_NA
id
----
1
2
3
4
我有一个这样的存储过程:
create procedure my_looping_procedure (@Country varchar(10))
as
begin
declare @MyTable varchar(50), @COUNTER int
set @COUNTER = 1
set @MyTable = concat('my_table_', @Country, '_NA')
while (@COUNTER <= (select max(id) from @MyTable))
begin
set @COUNTER = @COUNTER + 1
print @COUNTER
end
end
当我尝试编译该过程时,我得到了这个错误:
消息 1087,级别 16,状态 1,过程 my_looping_procedure,第 15 行 [批处理开始行 0]
必须声明表变量“@MyTable”
我尝试将 while 循环移动到它自己的小变量中:
create procedure my_looping_procedure (@Country varchar(10))
as
begin
declare @MyTable varchar(50),
@sql_loop varchar(max),
@COUNTER int
set @COUNTER = 1
set @MyTable = concat('my_table_', @Country, '_NA')
-- inner variable here
select @sql_loop = '
while (' + @COUNTER + '<= (select max(id) from ' + @MyTable + '))
begin
set ' + @COUNTER + ' = ' + @COUNTER + ' + 1
print ' + @COUNTER + '
end'
exec(@sql_loop)
end
编译但当我尝试执行它时返回错误exec my_looping_procedure:
消息 245,级别 16,状态 1,过程 my_looping_procedure,第 16 行 [批处理开始第 26 行]
将 varchar 值 'WHILE (' 转换为数据类型 int 时转换失败。
我尝试在@sql_loop 中声明和设置所有变量:
alter procedure my_looping_procedure (@Country varchar(10))
as
begin
declare @sql_loop varchar(max)
select @sql_loop = '
declare
@MyTable varchar(50),
@COUNTER INT
SET @COUNTER = 1
set @MyTable = concat(''my_table_'', ' + @Country + ', ''_NA'')
WHILE (@COUNTER <= (select max(id) from ' + @MyTable + '))
BEGIN
SET @COUNTER = @COUNTER + 1
print @COUNTER
end'
exec(@sql_loop)
end
这会编译,但执行时仍然出错:
消息 1087,第 16 层,状态 1,第 38 行
必须声明表变量“@MyTable”。
然后我再次在开头声明了@MyTable 变量:
alter procedure my_looping_procedure (@Country varchar(10))
as
begin
declare
@MyTable varchar(50),
@sql_loop varchar(max)
set @MyTable = concat('my_table_', @Country, '_NA')
select @sql_loop = '
declare
@MyTable varchar(50),
@COUNTER INT,
@Country varchar(10),
SET @COUNTER = 1
set @MyTable = concat(''my_table_'', ' + @Country + ', ''_NA'')
WHILE (@COUNTER <= (select max(id) from ' + @MyTable + ' ))
BEGIN
SET @COUNTER = @COUNTER + 1
print @COUNTER
end'
exec(@sql_loop)
end
这实际上编译但抱怨国家:
消息 207,第 16 层,状态 1,第 37 行
列名“US”无效。
最后,我把最初的表集语句注释掉了:
alter procedure my_looping_procedure (@Country varchar(10))
as
begin
declare
@MyTable varchar(50),
@sql_loop varchar(max)
-- set @MyTable = concat('my_table_', @Country, '_NA')
select @sql_loop = '
declare
@MyTable varchar(50),
@COUNTER INT,
@Country varchar(10),
@MaxCount int
SET @COUNTER = 1
set @MyTable = concat(''my_table_'', ' + @Country + ', ''_NA'')
WHILE (@COUNTER <= (select max(id) from ' + @MyTable + ' ))
BEGIN
SET @COUNTER = @COUNTER + 1
print @COUNTER
end'
exec(@sql_loop)
end
这会编译并运行,但什么也不做。
谁能弄清楚我做错了什么?
一些背景: 这是参数和 while 循环问题的示例,而不是实际代码。至于为什么这样做,最初的设计只是针对一个硬编码的国家。当添加更多国家/地区时,脚本会被复制并使用硬编码的新国家/地区。 最初的设计师不再在公司工作。我目前的任务只是制作一段通用的代码,无论我们添加多少个国家都可以使用。有数百个这样的脚本,项目上的时间和资源很少。
我非常感谢使用临时表的建议,但这些表用于其他进程。在我们解决流程的潜在问题之前,我们一直坚持这种设计。
【问题讨论】:
-
我看到一堆代码,但毫无疑问。你想做什么?
-
这似乎是设计问题,而不是(非常注入开放代码)。每个柜台不应该有一个表格,应该有一个表格,有一个国家列。另外,
LOOP的目的是在这里吗?你所做的就是PRINT每个ID;你真的想要做什么不需要循环。 -
事实上,你为什么要声明像
@Country这样的变量。我(愚蠢地)假设它们是参数,但事实并非如此。 -
这是参数和 while 循环问题的示例,而不是实际代码,因为代码处理的是我雇主的财务信息。至于为什么会这样,我从一个已经不在公司的人那里继承了设计。
标签: sql sql-server tsql stored-procedures