【发布时间】:2021-06-18 12:57:40
【问题描述】:
我有一个相当大的脚本,在这个问题中被缩小和简化了。总体原则是我有一些代码需要运行多次,每次迭代只需进行小幅调整。该脚本是用一个主循环构建的,其中有几个子循环。今天,整个 select 语句都被硬编码在循环中。我的想法是我可以编写一次选择语句,并且只让每个循环需要更改的部分成为循环中唯一更改的部分。目的是更容易维护。
脚本示例:
declare
@i1 int,
@i2 int,
@t nvarchar(50),
@v nvarchar(50),
@s nvarchar(max)
set @i1 = 1
while @i1 < 3
begin
if @i1 = 1
begin
set @i2 = 1
set @t = 'Ansokningsomgang'
set @s = '
select ' + @v + '_Ar,count(*) as N
from (
select left(' + @v + ',4) as ' + @v + '_Ar
from Vinnova_' + @t + '
) a
group by ' + @v + '_Ar
order by ' + @v + '_Ar
'
while @i2 < 4
begin
if @i2 = 1
begin
set @v = 'diarienummer'
exec sp_executesql
@stmt = @s,
@params = N'@tab as nvarchar(50), @var as nvarchar(50)',
@tab = @t, @var = @v
end
else if @i2 = 2
begin
set @v = 'utlysning_diarienummer'
exec sp_executesql
@stmt = @s,
@params = N'@tab as nvarchar(50), @var as nvarchar(50)',
@tab = @t, @var = @v
end
else if @i2 = 3
begin
set @v = 'utlysning_program_diarienummer'
exec sp_executesql
@stmt = @s,
@params = N'@tab as nvarchar(50), @var as nvarchar(50)',
@tab = @t, @var = @v
end
set @i2 = @i2 + 1
end
end
else
print('Nr: ' + cast(@i1 as char))
set @i1 = @i1 + 1
end
这个脚本不起作用。它贯穿但没有输出。如果我在@s 的声明上方declare @v 它可以工作,但是每次我需要更改@v 的值时我都需要declare @s。那么这样做就没有意义了。
@i1 的迭代次数远远超过此处显示的次数。
“if @i1”的 else 语句在实际脚本中不存在。在本例中,它替换了为 @i1 大声的每个值运行的一堆子循环。
我也尝试像这样执行@s:
exec(@s)
在每个循环中。结果一样。
那么我错过了什么?
数据库引擎是 MS SQL Server。
【问题讨论】:
-
你那里的东西很危险。它很容易受到注入攻击。老实说,如果我们这里有一个XY Problem,我不会感到惊讶。循环在 SQL 中几乎总是错误的解决方案,因为它是一种基于集合的语言。您在这里试图解决的真正问题是什么?
-
另外,我怀疑它不返回任何内容的原因是因为您将
@v连接到变量@s,但@v的值是NULL。{anything} + NULL = NULL -
我需要在多个表上运行几乎相同的选择语句,并且在每个表中我需要按计数检查不同数量的变量。变量在每个表中都有不同的名称,并且每个表的数量也不同。
-
“变量在每个表中都有不同的名称” 你这是什么意思?表格不能包含变量。
-
是的,我怀疑是 NULL 部分。但是我不知道如何解决这个问题而不会再次出现一堆硬编码的选择语句?
标签: sql-server tsql local-variables