我必须检查sql服务器实例的数据库子集中的表的子集中是否存在值。当心我需要这样做,因为我有30个具有相同架构名称和相似结构的数据库。单独查询所有数据库是浪费时间。
该查询会为现有表正确生成代码,但是对表中是否存在列的附加检查失败。 某些表中的列不存在,因此生成的代码不得包含对没有此列的表的查询。
要解决这个问题,我需要切实地找到一种方法,将sys.databases与sys.tables以及sys.columns结合起来。或以一种节省时间的方式查询所有必需数据库的替代方法。
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#temp') IS NOT NULL
DROP TABLE #temp
CREATE TABLE #temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
/*tables common root,
all tables i need to query start with this prefix and a number between 1 and 50
and some resulting tables do not exist
ex: dbo.Z_WBL_ASCHEDA23 exist in wbcto, while dbo.Z_WBL_ASCHEDA23 does not exist in db wbgtg
*/
DECLARE @TableName NVARCHAR(200)
SELECT @TableName = 'dbo.Z_WBL_ASCHEDA'
DECLARE @SQL NVARCHAR(MAX)
;WITH n(n) AS
(
SELECT 1
UNION ALL
SELECT n+1 FROM n WHERE n < 50
)
SELECT @SQL = STUFF((
SELECT CHAR(13)+'SELECT COUNT(1), ''' + db.name + ''', '''+
@TableName+CONVERT(VARCHAR, n.n)+''' FROM ' +@TableName+CONVERT(VARCHAR, n.n)
+ ' WHERE COALESCE(s_dettagli,'''') = ''CONTROLLATO'' '
+CHAR(13)
FROM sys.databases db
INNER JOIN n ON 1=1
INNER JOIN sys.tables t ON OBJECT_ID(db.name + '.' + @TableName+CONVERT(VARCHAR, n.n)) IS NOT NULL
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID and c.name = 's_dettagli'
/*join on columns not working, generates sql for tables without 's_dettagli' column and query fails*/
WHERE db.name like 'wb%' --check only databases starting with 'wb'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
select @SQL
INSERT INTO #temp (exist, DB, tbname)
EXEC sys.sp_executesql @SQL
SELECT *
FROM #temp t
where exist <> 0
编辑:添加从查询生成的一些SQL
SELECT COUNT(1), 'wb360', 'dbo.Z_WBL_ASCHEDA23' FROM wb360.dbo.Z_WBL_ASCHEDA23 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
SELECT COUNT(1), 'Wbbim', 'dbo.Z_WBL_ASCHEDA32' FROM Wbbim.dbo.Z_WBL_ASCHEDA32 WHERE COALESCE(s_dettagli,'') = 'CONTROLLATO'
第一个查询的表不包含“ s_dettagli”列
EDIT2:解决方案
EXEC sp_MSforeachdb '
IF ''?'' not like ''wb%''
RETURN
USE [?]
EXEC sp_MSforeachtable
@replacechar = ''!'',
@command1 = ''SELECT ''''?'''' AS db_name, ''''!'''' AS table_name, COUNT(*) FROM ! '',
@whereand = '' And Object_id In (
Select t.Object_id
From sys.objects t
INNER JOIN sys.columns c on c.Object_id = t.Object_id
Where t.name like ''''Z_WBL_ASCHEDA%''''
AND c.name = ''''s_dettagli'''' )'' '
答案 0 :(得分:0)
可以使用object_id字段将sys.columns连接到sys.tables(object_id是表本身的表示形式)。
sys.tables在查询的数据库上下文中运行,因此看不到另一个数据库中包含的表。 sys.databases可以在实例上的任何数据库上运行,并允许您查看同一实例上的其他数据库。因此,您不需要将表连接到数据库(这也是sys.tables中没有database_id字段的原因)。
我希望能有所帮助。如有任何澄清,请通知我。
答案 1 :(得分:0)
答案 2 :(得分:0)
我相信该脚本可以为您提供帮助:
SET NOCOUNT ON;
IF OBJECT_ID (N'tempdb.dbo.#Temp') IS NOT NULL
DROP TABLE #Temp
CREATE TABLE #Temp
(
exist INT
, DB VARCHAR(50)
, tbname VARCHAR(500)
)
DECLARE @SchemaName NVARCHAR(200)
DECLARE @TableName NVARCHAR(200)
DECLARE @ColumnName NVARCHAR(200)
DECLARE @SearchText NVARCHAR(200)
DECLARE @DBNameStartWith NVARCHAR(200)
DECLARE @SQL NVARCHAR(MAX)
SET @DBNameStartWith = 'wb'
SET @SchemaName = 'dbo'
SET @TableName = 'Z_WBL_ASCHEDA'
SET @ColumnName = 's_dettagli'
SET @SearchText = 'CONTROLLATO'
DECLARE @DatabaseName varchar(100)
DECLARE Crsr CURSOR FOR
SELECT name
FROM MASTER.sys.sysdatabases
WHERE name LIKE ''+@DBNameStartWith+'%'
OPEN Crsr
FETCH NEXT FROM Crsr INTO @DatabaseName
WHILE @@FETCH_STATUS = 0
BEGIN
IF ISNULL((SELECT COUNT(1) FROM SYS.TABLES T,SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name=@TableName AND C.name=@ColumnName),0)>0
BEGIN
SET @SQL = '
IF EXISTS (SELECT 1 FROM '+@DatabaseName+'.SYS.TABLES T,'+@DatabaseName+'.SYS.COLUMNS C WHERE T.object_id=C.object_id AND T.name='''+@TableName+''' AND C.name='''+@ColumnName+''')
BEGIN
SELECT COUNT(1),'''+@DatabaseName+''','''+@TableName+'''
FROM '+@DatabaseName+'.'+@SchemaName+'.'+@TableName+'
WHERE '+@ColumnName+'=''' +@SearchText+'''
END'
PRINT(@SQL)
INSERT INTO #Temp
EXEC sp_executesql @SQL
END
FETCH NEXT FROM Crsr INTO @DatabaseName
END
CLOSE Crsr
DEALLOCATE Crsr
SELECT * FROM #Temp