【问题标题】:SQL Server: issue with declaring variable in dynamic SQLSQL Server:在动态 SQL 中声明变量的问题
【发布时间】:2014-05-14 06:35:56
【问题描述】:

我创建了一个动态存储过程,如下所示。

我可以保存它而不会出错,但是当我执行它时,它似乎无法识别@temp 变量,因为它会引发以下错误:“必须声明表变量“@temp”。”

这可能是因为错误的引号/转义,如果我必须更改它以使其正确(我对 SQL 很陌生,因此某些引号可能错误或丢失)?

我的 SP(第一部分):

    @selection nvarchar(100)
AS
BEGIN

    SET NOCOUNT ON;

    BEGIN

    DECLARE @temp AS TABLE
    (
        ranking int,
        item nvarchar(100),
        groupCount int,
        groupName nvarchar(100)
    )

    DECLARE @sql nvarchar(max)

    SET @sql = '
    INSERT INTO @temp
    (       
                ranking,
                item,
                groupCount,
                groupName
    )
    SELECT      RANK() OVER(ORDER BY COUNT(*) desc, policy) [Rank],
                ' + @selection + ', 
                COUNT(*) AS groupCount,
                ''currentMonth'' AS groupName
    FROM        Log_PE 
    WHERE       CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), GETDATE(), 112) + ''01'', 112)
    GROUP BY    ' + @selection + '
    ORDER BY    groupCount desc, ' + @selection + '
        ...

非常感谢您在此提供的任何帮助,迈克。

【问题讨论】:

  • Dynamic Sql 有自己的 SCOPE 这个表变量对你的动态 sql 是不可见的,在你的动态 sql 中声明表变量。

标签: sql sql-server select dynamic dynamic-sql


【解决方案1】:

当您执行 EXEC 或 sp_executesql 时,您将获得另一个用于进程空间的名称空间(范围)。从表变量更改为本地临时表#temp。

下面是一个使用 sp_who2 的快速示例,说明了本地临时表的使用。

真诚的

J

代码片段

-- CREATE LOCAL TABLE
CREATE TABLE #WHO2
(
  [spid] int not null
, [status] varchar (255) not null
, [login] varchar (255) not null
, [host_name] varchar (255) not null
, [blk_by] varchar(10) not null
, [db_name] varchar (255) null
, [command] varchar (255) not null
, [cpu_time] int not null
, [disk_io] int not null
, [last_batch] varchar (255) not null
, [program_name] varchar (255) null
, [spid2] int not null
, [request_id] int not null
); ;

-- DYNAMIC SQL      
DECLARE @VAR_TSQL VARCHAR(MAX);      
SET @VAR_TSQL = 'INSERT #WHO2 EXEC sp_who2';
EXECUTE (@VAR_TSQL);
GO

-- TABLE PERSISTS UNTIL SPID (CONNECTION) IS BROKEN
SELECT * FROM #WHO2

【讨论】:

  • 也非常感谢!
【解决方案2】:

正如我在 cmets 部分中已经提到的,动态 Sql 有自己的范围,在该范围之外声明的任何变量对动态 sql 都不可见,您必须在动态 sql 中声明变量。如下所示....

SET @sql = N' DECLARE @temp AS TABLE
             (
              ranking int,
              item nvarchar(100),
              groupCount int,
              groupName nvarchar(100)
              )

INSERT INTO @temp
(       
            ranking,
            item,
            groupCount,
            groupName
)
SELECT      RANK() OVER(ORDER BY COUNT(*) desc, policy) [Rank],
            ' + @selection + ', 
            COUNT(*) AS groupCount,
            ''currentMonth'' AS groupName
FROM        Log_PE 
WHERE       CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6), GETDATE(), 112) + ''01'', 112)
GROUP BY    ' + @selection + '
ORDER BY    groupCount desc, ' + @selection + '

【讨论】:

  • 这个解决方案的问题是桌子消失了。要么存储为#temp,以便在后续处理中使用。我的许多实用程序脚本实际上将结果存储在 tempdb.dbo 中的小表中。
  • 他可以在动态 sql 中从该表中进一步向下选择。超出动态范围的临时表也不可见。
  • 我不会将 5000 行代码放入动态调用中。本地临时表是一个更好的解决方案。我避免使用表变量,因为它们的范围有限。
  • 另外,请查看 Aaron Betrand 关于不良 SQL 习惯的文章。 sqlblog.com/blogs/aaron_bertrand/archive/2009/10/16/… dateEsc 上的转换使列不是 SARGABLE,没有搜索索引。
  • 同意 :) ,与表变量相比,您可以使用临时表做更多事情。
【解决方案3】:

希望你一切都好, 好吧,我认为您可能会重新考虑使用变量表,因为当您执行 EXEC(@sql) 时,SQL 不会理解 @temp 变量的含义,我建议使用临时表而不是变量表,这是新代码:

BEGIN

    SET NOCOUNT ON;

    BEGIN

if object_id('temp') is not null
  drop table temp

create table temp
    (
        ranking int,
        item nvarchar(100),
        groupCount int,
        groupName nvarchar(100)
    )

    DECLARE @sql nvarchar(max)

    SET @sql = '
    INSERT INTO temp
    (       
                ranking,
                item,
                groupCount,
                groupName
    )
    SELECT      RANK() OVER(ORDER BY COUNT(*) desc, policy) [Rank],
                ' + @selection + ', 
                COUNT(*) AS groupCount,
                ''currentMonth'' AS groupName
    FROM        Log_PE 
    WHERE       CONVERT(DATE, dateEsc, 120) >= CONVERT(DATE, CONVERT(VARCHAR(6),     GETDATE(), 112) + ''01'', 112)
    GROUP BY    ' + @selection + '
    ORDER BY    groupCount desc, ' + @selection + '

...

if object_id('temp') is not null
  drop table temp

希望对你有帮助

【讨论】:

  • 一个简单的问题:我在哪里插入第二个“if object...”?在我执行这个之前?
  • 您可以使用它在 PS 末尾删除临时表,如果有效,请将其评为有效答案 :)
  • 您可以使用它在 PS 末尾删除临时表,如果有效,请将其评为有效答案 :)
猜你喜欢
  • 1970-01-01
  • 2016-12-11
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
相关资源
最近更新 更多