微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQL Server SP 错误消息 4145,级别 15,状态 1

如何解决SQL Server SP 错误消息 4145,级别 15,状态 1

当我尝试为选择和/或插入运行单个查询时,它可以工作。当我把它放在 SP 中并为所有 DB 运行它时,它出错了。

Msg 4145,Level 15,State 1,Line 45 非布尔类型的表达式 在预期条件的上下文中指定,靠近“Addr”。

Declare @command varchar(MAX)
Select @command = '
         USE [?]
         IF DB_NAME() not like ''%_VER'' 
            BEGIN RETURN END
         ElSE
          BEGIN 
             Insert Into [TEST_VER].[dbo].[TestTable] 
             (ClientName,ID,Type,Filled,FilledDate,Cancelled,CancelledDate,CancellationReason,Deleted,NumberOfPosition,Address,City,State,Country,Annual,AnnualMax,FeePercentage,Feetotal,Grossprofit,NetProfit,Rate,OTRate,CRate,COTRate,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
             select 
                 DB_NAME() as ClientName,Type.Description as Type,CancellationReason.Description as CancellationReason,Item.Deleted,Address.Description as Address,City.Description as City,ProvinceState.Description as State,Country.Description as Country,PayP.Annual,PayP.AnnualMaximum,PayP.FeePercentage,PayP.Feetotal,PayP.Grossprofit,PayP.NetProfit,PayT.Rate,PayT.OTRate,PayT.CRate,PayT.COTRate,PayT.Grossprofit,PayT.GrossMargin,PayT.ProfitMargin,PayT.RegularMarkup,PayT.OTMarkup
            from [Item]
            left join [Type] on Item.TypeID = Type.TypeID AND Type.LanguageId = 1 
            left join [CancellationReason] on Item.CancellationReasonID = CancellationReason.CancellationReasonID AND CancellationReason.LanguageID = 1
            left join [Address] on Item.LocationID = Address.AddressID  
            left join [City] on Address.CityId = City.CityID
            left join [ProvinceState] on Address.ProvinceStateId = ProvinceState.ProvinceStateID
            left join [Country] on Address.CountryId = Country.CountryID
            left join [PayP] on (Item.PaymentID=PayP.ID and Item.TypeID = 1)
            left join [PayT] on (Item.PaymentID=PayT.ID and Item.TypeID > 1)
         END'
EXEC sp_MSforeachdb @command

解决方法

简短的回应是你的sql命令太长了。

这个未记录的存储过程 sp_msforeachdb 不接受 varchar(max) 一样的 varchar。事实上,在 SQL SERVER 2019 上,如下面的 db -fiddle 所示,它只接受 2000 个字符,这会导致您的部分查询被截断。因此,您的连接表达式不完整,导致错误消息 Msg 4145,Level 15,State 1,Line 45 An expression of non-boolean type specified in a context where a condition is expected,near 'Addr'.

我建议使用较短的查询或在通常可访问的数据库中使用您的查询创建存储过程,然后从那里运行命令或重写您的查询以不同方式运行。我还在这个答案的末尾提供了一些建议。

您可以使用我在 sp_helptext 下面使用的存储过程来了解有关您的 db 版本中的定义的更多信息。

证明上述内容的代码和可重现的示例小提琴如下所示。

select @@version;
GO
| (No column name)                                                                                                                                                                                                                                                           |
| :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Microsoft SQL Server 2019 (RTM-CU6) (KB4563110) - 15.0.4053.23 (X64) <br>        Jul 25 2020 11:26:55 <br>        Copyright (C) 2019 Microsoft Corporation<br>        Express Edition (64-bit) on Windows Server 2019 Standard 10.0 <X64> (Build 17763: ) (Hypervisor)<br> |
 exec sp_helptext 'sp_msforeachdb'
 GO
| Text                                                                                                                                                    |
| :---------------------------------------------------------------------------------------------------------------------------------------------------

/*
 * The following table definition will be created by SQLDMO at start of each connection.
 * We don't create it here temporarily because we need it in Exec() or upgrade won't work.
 */

create proc sys.sp_MSforeachdb
    @command1 nvarchar(2000),@replacechar nchar(1) = N'?',@command2 nvarchar(2000) = null,@command3 nvarchar(2000) = null,@precommand nvarchar(2000) = null,@postcommand nvarchar(2000) = null
as
    set deadlock_priority low
    
    /* This proc returns one or more rows for each accessible db,with each db defaulting to its own result set */
    /* @precommand and @postcommand may be used to force a single result set via a temp table. */

    /* Preprocessor won't replace within quotes so have to use str(). */
    declare @inaccessible nvarchar(12),@invalidlogin nvarchar(12),@dbinaccessible nvarchar(12)
    select @inaccessible = ltrim(str(convert(int,0x03e0),11))
    select @invalidlogin = ltrim(str(convert(int,0x40000000),11))
    select @dbinaccessible = N'0x80000000'      /* SQLDMODbUserProf_InaccessibleDb; the negative number doesn't work in convert() */

    if (@precommand is not null)
        exec(@precommand)

    declare @origdb nvarchar(128)
    select @origdb = db_name()

    /* If it's a single user db and there's an entry for it in sysprocesses who isn't us,we can't use it. */
   /* Create the select */
    exec(N'declare hCForEachDatabase cursor global for select name from master.dbo.sysdatabases d ' +
            N' where (d.status & ' + @inaccessible + N' = 0)' +
            N' and (DATABASEPROPERTYEX(d.name,''UserAccess'') <> ''SINGLE_USER'' and (has_dbaccess(d.name) = 1))' )

    declare @retval int
    select @retval = @@error
    if (@retval = 0)
        exec @retval = sys.sp_MSforeach_worker @command1,@replacechar,@command2,@command3,1

    if (@retval = 0 and @postcommand is not null)
        exec(@postcommand)

   declare @tempdb nvarchar(258)
   SELECT @tempdb = REPLACE(@origdb,N']',N']]')
   exec (N'use ' + N'[' + @tempdb + N']')

    return @retval

这里我使用 2000 最大值运行查询,您将看到查询的一部分被截断

Declare @command varchar(2000)
Select @command = '
         USE [?]
         IF DB_NAME() not like ''%_VER'' 
            BEGIN RETURN END
         ElSE
          BEGIN 
             Insert Into [TEST_VER].[dbo].[TestTable] 
             (ClientName,ID,Type,Filled,FilledDate,Cancelled,CancelledDate,CancellationReason,Deleted,NumberOfPosition,Address,City,State,Country,Annual,AnnualMax,FeePercentage,FeeTotal,GrossProfit,NetProfit,Rate,OTRate,CRate,COTRate,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
             select 
                 DB_NAME() as ClientName,Type.Description as Type,CancellationReason.Description as CancellationReason,Item.Deleted,Address.Description as Address,City.Description as City,ProvinceState.Description as State,Country.Description as Country,PayP.Annual,PayP.AnnualMaximum,PayP.FeePercentage,PayP.FeeTotal,PayP.GrossProfit,PayP.NetProfit,PayT.Rate,PayT.OTRate,PayT.CRate,PayT.COTRate,PayT.GrossProfit,PayT.GrossMargin,PayT.ProfitMargin,PayT.RegularMarkup,PayT.OTMarkup
            from [Item]
            left join [Type] on Item.TypeID = Type.TypeID AND Type.LanguageId = 1 
            left join [CancellationReason] on Item.CancellationReasonID = CancellationReason.CancellationReasonID AND CancellationReason.LanguageID = 1
            left join [Address] on Item.LocationID = Address.AddressID  
            left join [City] on Address.CityId = City.CityID
            left join [ProvinceState] on Address.ProvinceStateId = ProvinceState.ProvinceStateID
            left join [Country] on Address.CountryId = Country.CountryID
            left join [PayP] on (Item.PaymentID=PayP.ID and Item.TypeID = 1)
            left join [PayT] on (Item.PaymentID=PayT.ID and Item.TypeID > 1)
         END'
select 1
select @command
GO
| (No column name) |
| ---------------: |
|                1 |
USE [?]
         IF DB_NAME() not like '%_VER' 
            BEGIN RETURN END
         ElSE
          BEGIN 
             Insert Into [TEST_VER].[dbo].[TestTable] 
             (ClientName,PayT.OTMarkup
            from [Item]
            left join [Type] on Item.TypeID = Type.TypeID AND Type.LanguageId = 1 
            left join [CancellationReason] on Item.CancellationReasonID = CancellationReason.CancellationReasonID AND CancellationReason.LanguageID = 1
            left join [Address] on Item.LocationID = Address.AddressID  
            left join [City] on Address.CityId = City.CityID
            left join [ProvinceState] on Address.ProvinceStateId = P

dbfiddle here

@Larnu 还提出了一些关于替代方案的建议,例如 option 1option 2,您可以在自己的时间考虑。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。