我创建了以下查询,该查询将从所有数据库中获取数据。当我执行查询时,我得到错误的无效列ID。我已经调查并发现主数据库中列出了表tbl_table_A(示例),并且该表没有列ID。我已排除了该数据库主数据库,但不确定为什么查询仍在调用主数据库。请告知
查询:
CREATE TABLE ##tbl_data
(
[database_name] NVARCHAR(500),
id INT,
last_run DATETIME,
[next_run] DATETIME,
last_run_status NVARCHAR(500)
)
DECLARE @StartDate NVARCHAR(MAX)
DECLARE @EndDate NVARCHAR(MAX)
DECLARE @strSQL NVARCHAR(MAX)
SET @StartDate = '10-Dec-2019 00:12:59'
SET @EndDate = '10-Dec-2019 00:17:59'
SET @strSQL =
'
USE [?]
IF ''?'' <> ''master'' AND ''?'' <> ''model'' AND ''?'' <> ''msdb'' AND ''?'' <> ''tempdb''
BEGIN
IF OBJECT_ID(''tbl_table_A'') IS NULL
RETURN;
insert into ##tbl_data
SELECT ''?'', id,last_run,next_run,last_run_status
FROM dbo.tbl_table_A nolock
WHERE last_run between cast ('''+@StartDate+''' as Datetime2) and cast ('''+@EndDate+''' as Datetime2)
END'
EXEC dbo.sp_msforeachdb @strSQL
Select * from ##tbl_data
Drop table ##tbl_data
我已经排除了该数据库主服务器,但不确定为什么查询仍然存在调用主数据库
[否,您的代码不会“调用” master
。这是您使用打印而不是插入的代码。这样,您可以查看究竟检查了什么db,以及那里是否有您的表:
declare @strSQL NVARCHAR(MAX)
SET @strSQL =
'
USE [?]
IF ''?'' <> ''master'' AND ''?'' <> ''model'' AND ''?'' <> ''msdb'' AND ''?'' <> ''tempdb''
BEGIN
print ''?''
IF OBJECT_ID(''tbl_table_A'') IS NULL
begin
print ''there is no table tbl_table_A''
print ''----------------''
RETURN;
end
print ''***** THERE IS table tbl_table_A *****''
print ''----------------''
END'
EXEC dbo.sp_msforeachdb @strSQL
我一直喜欢对这些类型的问题采用不同的方法。首先,我真的不喜欢游标,您真的不需要这里的游标。另外,sp_msforeachdb不仅未公开,而且还存在一些问题。有时会跳过数据库,而且似乎没有人真正知道为什么。亚伦·伯特兰(Aaron Bertrand)对此进行了讨论,并在此提供了更好的选择。 https://sqlblog.org/2010/12/29/a-more-reliable-and-more-flexible-sp_msforeachdb
我更喜欢做下面的事情。没有循环,也不会遇到像跳表这样的怪异行为。它还不需要可能存在严重的并发问题的全局临时表。这需要两个动态sql语句。第一个获取具有要查找表的数据库列表。然后,我们使用该数据针对要搜索的数据库列表生成动态sql语句。
if OBJECT_ID('tempdb..#Databases') is not null
drop table #Databases
DECLARE @StartDate NVARCHAR(MAX)
, @EndDate NVARCHAR(MAX)
, @strSQL NVARCHAR(MAX)
SELECT @StartDate = '20191210 00:12:59'
, @EndDate = '20191210 00:17:59'
, @strSQL = ''
declare @TableName sysname = 'tbl_table_A'
select @strSQL = @strSQL + 'select ''' + d.name + ''' from ' + quotename(d.name) + '.sys.tables where name = ''' + @TableName + ''' union all '
from sys.databases d
select @strSQL = left(@strSQL, len(@strSql) - 10) --this removes the last union all
CREATE TABLE #Databases
(
DatabaseName sysname
)
--select @strSQL
insert #Databases
(
DatabaseName
)
exec sp_executesql @strSQL
set @strSQL = ''
select @strSQL = @strSQL + 'select ''' + d.DatabaseName + ''', id, last_run, next_run, last_run_status from ' + quotename(d.DatabaseName) + '.dbo.' + @TableName + ' where last_run between @_StartDate and @_EndDate union all '
from #Databases d
select @strSQL = left(@strSQL, len(@strSql) - 10)
--select @strSQL
exec sp_executesql @strSQL, N'@_StartDate datetime, @_EndDate datetime', @_StartDate = @StartDate, @_EndDate = @EndDate