【问题标题】:How to set value to variable using 'execute' in t-sql?如何在 t-sql 中使用“执行”将值设置为变量?
【发布时间】:2021-12-09 22:11:17
【问题描述】:
DECLARE @dbName nvarchar(128) = 'myDb'
DECLARE @siteId int 
exec ('SELECT TOP 1 @siteId = Id FROM ' + @dbName + '..myTbl')  
select @siteId

当我运行上面的脚本时,出现以下错误

Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "@siteId".

(1 row(s) affected)

为什么以及如何解决它?

谢谢

【问题讨论】:

    标签: sql-server tsql


    【解决方案1】:

    您可以在 sp_executesql 中使用输出参数。

    DECLARE @dbName nvarchar(128) = 'myDb'
    DECLARE @siteId int 
    DECLARE @SQL nvarchar(max) = N'SELECT TOP 1 @outputFromExec = Id FROM ' + quotename(@dbName) + N'..myTbl'
    exec sp_executesql @SQL, N'@outputFromExec int out', @siteId out
    select @siteId
    

    【讨论】:

    • +1 这是更好的方法。我看到了一个参数化的数据库名称并关闭了 sp_executesql...
    • 酷,我找到了我要找的东西!
    • 之后我无法使用@siteId...它返回NULL。执行行工作正常...
    • @PauloHenrique 不要忘记EXEC 行中的最后一个OUT,否则它会静默失败。
    【解决方案2】:

    动态 SQL 与外部的作用域不同,调用 SQL: 所以@siteid 不被识别

    您必须在动态 SQL 之外使用临时表/表变量:

    DECLARE @dbName nvarchar(128) = 'myDb'
    DECLARE @siteId TABLE (siteid int)
    
    INSERT @siteId
    exec ('SELECT TOP 1 Id FROM ' + @dbName + '..myTbl')  
    
    select * FROM @siteId
    

    注意:没有 ORDER BY 的 TOP 是没有意义的。表没有自然的、隐含的或内在的排序。任何订单只保证最外层的ORDER BY

    【讨论】:

    • “没有 ORDER BY 的 TOP 是没有意义的”——无意义在这里可能有点强,也许我想要的只是 1 条记录,我不在乎哪家,即今晚我应该在哪家餐厅吃饭?
    • @RyanfaeScotland:也许,但是 SQL 中没有ANY() 函数可以提供任意行。否则,我希望我的查询每次都以相同的方式运行,而不是依赖于一些假定的顺序。
    • 您的注释在大多数实际情况下根本不正确。表上维护的聚集索引将确保表结果的一致、可预测的顺序。
    • @Matt:您会在每次更新或插入会导致碎片的情况下维护聚集索引吗?
    • 与时间相关的变量或代理确保您的排序按时间顺序得到隐式维护。你的观点可能是一个有效的观点,但说没有“自然、隐含或内在的排序”这一点是不正确的,这就是我的观点。记录的物理存储位置具有可预测性,这转化为TOP 排序中的时间相关可预测性。当然,这并不假定它对于给定查询的目的是有用的顺序,但它是可预测的。
    【解决方案3】:

    你可以像下面这样尝试

    DECLARE @sqlCommand NVARCHAR(4000)
    DECLARE @ID INT
    DECLARE @Name NVARCHAR(100)
    SET @ID = 4
    SET @sqlCommand = 'SELECT @Name = [Name]
    FROM [AdventureWorks2014].[HumanResources].[Department]
    WHERE DepartmentID = @ID'
    EXEC sp_executesql @sqlCommand, N'@ID INT, @Name NVARCHAR(100) OUTPUT',
    @ID = @ID, @Name = @Name OUTPUT
    SELECT @Name ReturnedName
    

    来源:blog.sqlauthority.com

    【讨论】:

      【解决方案4】:
      SET ANSI_NULLS ON
      GO
      SET QUOTED_IDENTIFIER ON
      GO
      -- =============================================
      -- Author:      Andrew Foster
      -- Create date: 28 Mar 2013
      -- Description: Allows the dynamic pull of any column value up to 255 chars from regUsers table
      -- =============================================
      ALTER PROCEDURE dbo.PullTableColumn
      (
          @columnName varchar(255),
          @id int
      )
      AS
      BEGIN
          -- SET NOCOUNT ON added to prevent extra result sets from
          -- interfering with SELECT statements.
          SET NOCOUNT ON;
      
          DECLARE @columnVal TABLE (columnVal nvarchar(255));
      
          DECLARE @sql nvarchar(max);
          SET @sql = 'SELECT ' + @columnName + ' FROM regUsers WHERE id=' + CAST(@id AS varchar(10));
          INSERT @columnVal EXEC sp_executesql @sql;
      
          SELECT * FROM @columnVal;
      END
      GO
      

      【讨论】:

        【解决方案5】:

        执行查询稍作改动即可解决问题:

        DECLARE @dbName nvarchar(128) = 'myDb'
        DECLARE @siteId int 
        exec ('SELECT TOP 1 **''@siteId''** = Id FROM ' + @dbName + '..myTbl')  
        select @siteId
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-03
          相关资源
          最近更新 更多