SQL 服务器 SP 错误消息 4145,级别 15,状态 1
SQL Server SP error Msg 4145, Level 15, State 1
当我尝试 运行 对 select and/or 插入的单独查询时,它起作用了。当我把它放在 SP 中并为所有数据库 运行 时,它会出错。
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'.
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,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
select
DB_NAME() as ClientName,
ID,
Type.Description as Type,
Filled,
FilledDate,
Cancelled,
CancelledDate,
CancellationReason.Description as CancellationReason,
Item.Deleted,
NumberOfPosition,
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
来了解有关您的数据库版本中的定义的更多信息。
证明上述内容的代码和可重现示例fiddle如下所示。
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,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
select
DB_NAME() as ClientName,
ID,
Type.Description as Type,
Filled,
FilledDate,
Cancelled,
CancelledDate,
CancellationReason.Description as CancellationReason,
Item.Deleted,
NumberOfPosition,
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,ID,Type,Filled,FilledDate,Cancelled,CancelledDate,CancellationReason,Deleted,NumberOfPosition,Address,City,State,Country,Annual,AnnualMax,FeePercentage,FeeTotal,GrossProfit,NetProfit,Rate,OTRate,CRate,COTRate,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
select
DB_NAME() as ClientName,
ID,
Type.Description as Type,
Filled,
FilledDate,
Cancelled,
CancelledDate,
CancellationReason.Description as CancellationReason,
Item.Deleted,
NumberOfPosition,
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 = P
db<>fiddle here
当我尝试 运行 对 select and/or 插入的单独查询时,它起作用了。当我把它放在 SP 中并为所有数据库 运行 时,它会出错。
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'.
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,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
select
DB_NAME() as ClientName,
ID,
Type.Description as Type,
Filled,
FilledDate,
Cancelled,
CancelledDate,
CancellationReason.Description as CancellationReason,
Item.Deleted,
NumberOfPosition,
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
来了解有关您的数据库版本中的定义的更多信息。
证明上述内容的代码和可重现示例fiddle如下所示。
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,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup) select DB_NAME() as ClientName, ID, Type.Description as Type, Filled, FilledDate, Cancelled, CancelledDate, CancellationReason.Description as CancellationReason, Item.Deleted, NumberOfPosition, 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,ID,Type,Filled,FilledDate,Cancelled,CancelledDate,CancellationReason,Deleted,NumberOfPosition,Address,City,State,Country,Annual,AnnualMax,FeePercentage,FeeTotal,GrossProfit,NetProfit,Rate,OTRate,CRate,COTRate,GrossProfit,GrossMargin,ProfitMargin,RegularMarkup,OTMarkup)
select
DB_NAME() as ClientName,
ID,
Type.Description as Type,
Filled,
FilledDate,
Cancelled,
CancelledDate,
CancellationReason.Description as CancellationReason,
Item.Deleted,
NumberOfPosition,
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 = P
db<>fiddle here