2017-08-16 127 views
1

这是故事。我试图从主表和一系列名称基于主表中的值的表中提取元数据。没有外键。标量变量不填充

如果有一个键,那就是来自主表的主键被附加到子表的末尾。主表是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 
+1

格式化您的问题,并使其成为[最小,完整和可验证的示例](https://stackoverflow.com/help/mcve),重点放在* minimial *开始。 – scsimon

回答

0

当您声明变量时,可见性仅限于声明它们的范围。当您执行语句时,会创建一个新的会话,从而创建一个新的范围。

你需要做的是输出使用呼叫的OUTPUT参数sp_executesql标量变量:

SET @sql='Set @keytypenum = ...'; 
EXEC sp_executesql @sql,N'@keytypenum INT OUT', @keytypenum OUTPUT; 

注意,@sql变量需要是一个NVARCHAR

你可以找到更多的例子here

+0

这真棒,很清楚地解决了我的问题,立即查询第一个问题。跟进问题,如果你不介意。我的第二个查询使用表变量,keytypedata。我希望用这个“虚拟”表来总结我的所有输出结果。当我收到错误时,“必须声明表变量@keytypedata”。我担心我无法将行附加到表中,因为它会在每次EXEC后重置。 sp_executesql会解决这个问题,还是我搞砸了? (非常感谢你! – Brad

+0

@Brad Hi Brad。表值参数总是只读的,不能用于输出(参见[这个问题](https://stackoverflow.com/q/19270727/243373)你可以使用临时表,而不必将它们作为参数传递,只要会话处于活动状态,它们暂时存在,就好像它们是普通表一样, –

+0

@Brad如果我的答案解决了你的问题,请检查答案旁边的复选标记(✔)。阅读更多关于此处的信息:[当某人回答我的问题时该怎么办?](https://stackoverflow.com/help/someone-answers)祝你好运! –

0

是的,你不能那样做。你的变量超出了范围。

每个变量的范围仅限于它自己的会话,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建议是个不错的主意。