标量变量不填充

时间:2017-08-16 20:32:25

标签: sql sql-server

这是故事。我试图从主表和一系列表中提取元数据,这些表的名称基于主表中的值。没有外键。

如果有密钥,则来自主表的主键将附加到子表的末尾。主表格为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

2 个答案:

答案 0 :(得分:0)

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

您需要做的是在调用sp_executesql时使用OUTPUT参数输出标量变量:

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

请注意,@ sql变量必须是NVARCHAR

您可以找到更多示例here

答案 1 :(得分: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建议是一个好主意。