标量变量不填充
这是故事。我试图从主表和一系列名称基于主表中的值的表中提取元数据。没有外键。标量变量不填充
如果有一个键,那就是来自主表的主键被附加到子表的末尾。主表是hsi.keytypetable
。子表格是hsi.keyitemxxx
,其中xxx是从主表中抽取的值(keytypenum
)。
所有我想要从子表中拉现在是一个值的计数。在当前的表单中,查询@sql1
无法填充@keytypenum
,但当我查看查询本身并在单独的窗口中运行它时,它的工作方式类似于冠军。这个问题继续在第二个查询,@sql2
,在那里我得到的错误,
必须声明标量变量“@keytypenum”
至于我可以告诉大家,我已经声明了事情。我猜我在每个查询中都有类似的语法问题。
SET CONCAT_NULL_YIELDS_NULL OFF
declare @keytypedata table
(
Keyword varchar(50),
DateType varchar(50),
"Length" int,
"Count" int
)
declare @keywordcount int
declare @x int = 1
declare @keytypenum int
declare @sql1 varchar(max)
declare @sql2 varchar(max)
/* Determine how many records are in the master table so that I can cycle thru each one, getting the count of the child tables. */
Select @keywordcount = (Select count(*) from hsi.keytypetable)
/* @x is the counter. I'll cycle through each row in the master using a WHILE loop */
WHILE @x < @keywordcount+1
BEGIN
/* One row at a time, I'll pull the KEYTYPENUM and store it in @keytypenum. (I don't really need the order by, but I like having things in order!)
** I take the rows in order b using my counter, @x, as the offset value and fetch only 1 row at a time. When I run this query in a separate screen,
** it works well, obviously with providing a fixed offset value. */
set @sql1 =
'Set @keytypenum =
(Select
KEYTYPENUM
from hsi.keytypetable
order by KEYTYPENUM
OFFSET ' + cast(@x as varchar(4)) + ' ROWS
FETCH NEXT 1 ROWS ONLY)'
EXEC(@sql1)
/* For debugging purposes, I wanted to see that @keytypenum got assigned. This is working. */
print 'KeyTypeNum: '+cast(@keytypenum as varchar(4))
/* I don't know why I had to be my table variable, @keytypedata, in single quotes at the beginning, but it wouldn't work if
** I didn't. The problem comes later on with restricting the query by the aforementioned @keytypenum. Remember this variable is an INT. All values
** for this field are indeed integers, and there are presently 955 rows in the table. The maximum value is 1012, so we're safe with varchar(4).
*/
SET @sql2 =
'Insert into ' + '@keytypedata' + '
Select
keytype,
CASE
WHEN k.datatype = 1 THEN ''Numeric 20''
WHEN k.datatype = 2 THEN ''Dual Table Alpha''
WHEN k.datatype = 3 THEN ''Currency''
WHEN k.datatype = 4 THEN ''Date''
WHEN k.datatype = 5 THEN ''Float''
WHEN k.datatype = 6 THEN ''Numeric 9''
WHEN k.datatype = 9 THEN ''DateTime''
WHEN k.datatype = 10 THEN ''Single Table Alpha''
WHEN k.datatype = 11 THEN ''Specific Currency''
WHEN k.datatype = 12 THEN ''Mixed Case Dual Table Alpha''
WHEN k.datatype = 13 THEN ''Mixed Case Single Table Alpha''
END,
keytypelen,
(Select count(*) from hsi.keyitem' + cast(@keytypenum as varchar(4)) + ')
FROM
hsi.keytypetable k
where
k.keytypenum = ' + cast(@keytypenum as varchar(4))+''
/* Printing out where I am with cycling thru the master table, just for troubleshooting*/
print @x
/* Increment the counter*/
set @x = @x + 1
END
/* This query is simply to display the final results. */
select *
from @keytypedata
order by 1
/* Print statements below are for troubleshooting. They should show what the 2 queries currently look like. */
Print @sql1
Print @sql2
当您声明变量时,可见性仅限于声明它们的范围。当您执行语句时,会创建一个新的会话,从而创建一个新的范围。
你需要做的是输出使用呼叫的OUTPUT
参数sp_executesql标量变量:
SET @sql='Set @keytypenum = ...';
EXEC sp_executesql @sql,N'@keytypenum INT OUT', @keytypenum OUTPUT;
注意,@sql变量需要是一个NVARCHAR
。
你可以找到更多的例子here。
这真棒,很清楚地解决了我的问题,立即查询第一个问题。跟进问题,如果你不介意。我的第二个查询使用表变量,keytypedata。我希望用这个“虚拟”表来总结我的所有输出结果。当我收到错误时,“必须声明表变量@keytypedata”。我担心我无法将行附加到表中,因为它会在每次EXEC后重置。 sp_executesql会解决这个问题,还是我搞砸了? (非常感谢你! – Brad
@Brad Hi Brad。表值参数总是只读的,不能用于输出(参见[这个问题](https://stackoverflow.com/q/19270727/243373)你可以使用临时表,而不必将它们作为参数传递,只要会话处于活动状态,它们暂时存在,就好像它们是普通表一样, –
@Brad如果我的答案解决了你的问题,请检查答案旁边的复选标记(✔)。阅读更多关于此处的信息:[当某人回答我的问题时该怎么办?](https://stackoverflow.com/help/someone-answers)祝你好运! –
是的,你不能那样做。你的变量超出了范围。
每个变量的范围仅限于它自己的会话,exec()
基本上创建了一个新的会话。
这将引发和错误@x
未定义:
declare @x int = 1
exec ('select @x')
本作将会:
exec ('declare @x int = 2')
exec ('select @x')
这:
exec ('declare @x int = 2')
select @x
你必须要做得像这个:
exec ('declare @x int = 2; select @x')
或以其他方式将结果返回。 @ TT。答案中的sp_executesql
建议是个不错的主意。
格式化您的问题,并使其成为[最小,完整和可验证的示例](https://stackoverflow.com/help/mcve),重点放在* minimial *开始。 – scsimon