【问题标题】:Must declare the scalar variable error in subselect SQL必须在子选择 SQL 中声明标量变量错误
【发布时间】:2012-10-29 08:18:22
【问题描述】:

我正在尝试创建一个 SQL 脚本,该脚本将创建一个易于更新的脚本,其中另一个人只需要更新所涉及的常量然后运行查询,但是在子选择中使用声明的变量时我遇到了麻烦。

我知道这是因为声明的变量不在子选择的范围内,但似乎无法找到解决方法。

这是目前的代码:

DECLARE @_logdb varchar(30) = 'nb_tablename';
DECLARE @_sitedb varchar(30) = 'nb_tablename_site';
DECLARE @_backtodate varchar(30) = '2012-10-10';
DECLARE @_sitename varchar(50) = 'bikehaven';

UPDATE
    [@_sitedb].[dbo].[bike] 
SET [bikeStatus] = 'active' 
WHERE bikeID in (
    SELECT 
substring(
    [event], 
    CHARINDEX('bike ID' , [event]) + LEN('bike ID '),
    CHARINDEX(
        ')', 
        [event],
        CHARINDEX('bike ID' , [event])
    ) - (CHARINDEX('bike ID' , [event]) + LEN('bike ID '))
) as 'ID'
from [@_logdb].[dbo].[logs] 
where 
    user_name = 'john' AND 
    event_type = 'Deleted bike' AND 
    CHARINDEX('bike ID' , [event]) > 0 AND 
    date_time > @_backtodate AND 
    siteID = (
        SELECT id 
        from [@_logdb].[dbo].[sites] 
        WHERE site_name = @_sitename
    )
)

实际上造成问题的两个变量是@_backtodate@_sitename,但我也知道如果我用真正的字符串替换这些变量,我会得到错误,说[@_sitedb].[dbo].[bike] 也是一个问题。

我已经进行了相当多的谷歌搜索,尝试使用临时表进行子查询以及将 SQL 本身定义为变量,然后在其上运行 EXEC 命令,但无济于事。

编辑:我已按照Andomar 的指示应用了更改,方法是将查询本身提取到声明变量中,然后运行它,这确实是对其中一个错误的修复,但是,即使进行了该修复,我仍然遇到必须为 @_back to date@_sitename 定义标量变量错误。

解决方案:Alexander Fedorenko 建议的更改最终给了我最后一点难题。在动态 SQL 中,不能通过参数将表名用作显式替换,而这些对于 actual 变量值非常有效。

简而言之: - 使查询成为字符串变量。 - 任何需要发生的表名替换,您都可以通过字符串连接添加(意味着输出字符串需要是一个有效的查询) - 将任何变量参数传递给存储过程SP_executesql

最终的工作代码由Alexander Fedorenko指定。

【问题讨论】:

  • "这是因为声明的变量不在子选择的范围内" - 不,不是。你误诊了这个问题。正如@Andomar 指出的那样,主要问题是您不能在 SQL Server 期望遇到名称的地方使用字符串变量(例如在表的名称中)

标签: sql subquery declare scalar


【解决方案1】:

procedure sp_executesql 允许使用参数。 Using sp_executesql

DECLARE @_logdb varchar(30) = 'nb_tablename';
DECLARE @_sitedb varchar(30) = 'nb_tablename_site';
DECLARE @_backtodate varchar(30) = '2012-10-10';
DECLARE @_sitename varchar(50) = 'bikehaven';

DECLARE @_SQL nvarchar(max)
SET @_SQL = '
UPDATE
    ' + @_sitedb + '.[dbo].[bike] 
SET [bikeStatus] = ''active'' 
WHERE bikeID in (
    SELECT 
substring(
  [event],
CHARINDEX(''bike ID'' , [event]) + LEN(''bike ID ''),
CHARINDEX(
'')'', 
[event],
CHARINDEX(''bike ID'' , [event])
) - (CHARINDEX(''bike ID'' , [event]) + LEN(''bike ID ''))
) as ''ID''
from ' + @_logdb + '.[dbo].[logs]
where 
user_name = ''john'' AND 
event_type = ''Deleted bike'' AND
CHARINDEX(''bike ID'' , [event]) > 0 AND
date_time > @_backtodate AND
siteID = (
SELECT id 
from ' + @_logdb + '.[dbo].[sites]
WHERE site_name = @_sitename
    )
)'
EXEC sp_executesql @_SQL, N'@_backtodate varchar(30), @_sitename varchar(50)', @_backtodate, @_sitename

【讨论】:

    【解决方案2】:

    您不能使用变量作为表名。所以这行不通:

    from [@_logdb].[dbo].[logs] 
    

    如果你真的想要变量表名,唯一的选择是动态 SQL。使用 SQL 创建一个nvarchar(max) 变量,并使用sp_executesqlexec 运行它。

    declare @sql nvarchar(max)
    set @sql = 'select * from ' + @tablename
    exec (@sql)
    

    【讨论】:

    • 我添加了您的更改,这很好,解决了我的表名问题,但是我仍然遇到@_backtodate@_sitename 变量的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    相关资源
    最近更新 更多