我有以下问题:我想在SQL Server上的多个数据库上执行查询。每个客户都有一个单独的数据库这些都有完全相同的表,他们的名字相似。所以有一个数据库kde_01_Miller
,然后是kde_02_Mueller
等等......
我想在每个数据库中执行查询。
以下是我的尝试:
DECLARE @name VARCHAR(100) -- database name
DECLARE @dothis nvarchar(200)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name like 'kde_0%'
order by name
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
set @dothis = 'use [' + @name + ']'
exec sp_executesql @dothis
/* Start query */
select description from dbo.basicdata
/* End query */
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
问题是查询无法正常运行。 use
语句似乎不起作用。我得到了每个数据库的结果,但结果总是相同的,取决于我正在进行查询的数据库。
我也尝试过以下内容并且它有效:我没有使用while循环,而是执行了此操作:
WHILE @@FETCH_STATUS = 0
BEGIN
set @dothis= 'select description from ' + QUOTENAME(@name) + '.dbo.basicdata'
exec sp_executesql @dothis
FETCH NEXT FROM db_cursor INTO @name
END
但我不喜欢这种方式,因为每张桌子都需要quotename(@name)
。
如何让第一个示例正常工作?
答案 0 :(得分:1)
这是不可能的,因为sp_executesql是作为自己独立的批次执行的,这意味着你实际上已经"使用"其他数据库,但仅限于我之前提到的那些批次
我会更加清楚,这段代码是批次,因为没有" GO &# 34;命令里面(读我的SQL注释):
DECLARE @name VARCHAR(100) -- database name
DECLARE @dothis nvarchar(200)
DECLARE db_cursor CURSOR FOR
SELECT name
FROM master.dbo.sysdatabases
WHERE name like 'kde_0%'
order by name
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @name
WHILE @@FETCH_STATUS = 0
BEGIN
set @dothis = 'use [' + @name + ']'
-- this will create another batch and execute the @dothis
-- it'll have nothing todo with your current executing batch,
-- which is calling the sp_executesql
exec sp_executesql @dothis
/* Start query */
select description from dbo.basicdata
/* End query */
FETCH NEXT FROM db_cursor INTO @name
END
CLOSE db_cursor
DEALLOCATE db_cursor
所以,只剩下一条路了,在@dothis中写下你想对数据库做的任何事情:
declare @dothis nvarchar(max)
set @dothis = '
use [' + @name + ']
-- query start
Select description from dbo.basicdata
-- query end
'
exec sp_executesql @dothis
答案 1 :(得分:0)
虽然这个问题已经得到解答,但我认为我提供的第二个答案我认为更好。您可以生成动态SQL来查询多个数据库,而不是使用Cursor。
DECLARE @sql NVARCHAR(Max);
SELECT @sql = COALESCE(@sql, '') + 'SELECT * FROM ' + [name] + '.sys.tables' + CHAR(13)
FROM sys.databases
PRINT @sql
EXEC sp_executesql @sql
上面的SQL将生成以下SQL。
SELECT * FROM master.sys.tables
SELECT * FROM tempdb.sys.tables
SELECT * FROM model.sys.tables
SELECT * FROM msdb.sys.tables
SELECT * FROM StackOverflow.sys.tables
SELECT * FROM AdventureWorks2012.sys.tables
SELECT * FROM AdventureWorksDW2012.sys.tables
如您所见,我能够针对多个数据库运行查询。如果我愿意,我甚至可以将数据联合起来。
答案 2 :(得分:0)
尽管在针对同一问题的解决方案中已经给出了答案,但我还是写了此查询。 它提供了数据,并显示了提供答案的数据库源。 请注意,排序依据仅是显示双精度值,但会减慢结果速度
declare @results table (
name varchar(50),
clientnr numeric(20) ,
dbname_source varchar(20)
);
insert @results
exec sp_msforeachdb N'
use [?]
if left(''?'',3) = ''ons'' -- only execute the query against databases that match the naming pattern in this example starting with ons (use your own database names make sure to exclude systemdatabases
--and ''?'' <> ''MIS_MTA''
begin
--select script that to be executed over multiple databases
select distinct
c.name,
c.identificationNo as numeric,
d.table_catalog
from [?].dbo.clients as c , [?].INFORMATION_SCHEMA.COLUMNS as d
where 1=1
and isnumeric(c.identificationNo) = 1
end;
';
select * from @results
where
isnumeric(clientnr) = 1
order by 2
;
示例结果:
name clientnr dbname_source
TestclientA 9000 OnsDB
TestclientA 9000 OnsDB_Fixed
Storcken 9999 OnsDB_Fixed
Storcken 9999 OnsDB