Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 动态使用声明_Sql Server_Select_Multi Table_Multi Database - Fatal编程技术网

Sql server 动态使用声明

Sql server 动态使用声明,sql-server,select,multi-table,multi-database,Sql Server,Select,Multi Table,Multi Database,我正在寻找是否有人有任何理由为什么下面的代码是一个坏主意 这个挑战涉及我在几个不同的地方和环境中遇到的一个挑战。如何对多个数据库中相同的表结构运行相同的查询。这对于许多尝试多站点安装的小型ERP来说是一个问题。每个位置在服务器上都有匹配的表和不同的数据库。在报告数据收集时,通常会在每个数据库中部署一个proc,该数据库是一个精确的副本。我在有多达14个独立站点的站点中看到了这一点。代码扩散和管理部署可能非常具有挑战性。最近,我发现了一个没有人提出过的想法,至少我还没有发现,虽然过于简单化,但似乎

我正在寻找是否有人有任何理由为什么下面的代码是一个坏主意

这个挑战涉及我在几个不同的地方和环境中遇到的一个挑战。如何对多个数据库中相同的表结构运行相同的查询。这对于许多尝试多站点安装的小型ERP来说是一个问题。每个位置在服务器上都有匹配的表和不同的数据库。在报告数据收集时,通常会在每个数据库中部署一个proc,该数据库是一个精确的副本。我在有多达14个独立站点的站点中看到了这一点。代码扩散和管理部署可能非常具有挑战性。最近,我发现了一个没有人提出过的想法,至少我还没有发现,虽然过于简单化,但似乎可行。我不知道的是,我是否遗漏了一些微妙的东西,或者为什么这是个坏主意的技术原因

守则:

DECLARE @i AS INT 
SET @i = 1

WHILE @i < 3
BEGIN
    IF @i = 1 USE [DB1]
    IF @i = 2 USE [DB2]

    INSERT INTO ThirdDB.dbo.ReportTable (field)
        SELECT TOP 1 SomeNumber 
        FROM CommonTable WITH (NOLOCK)

    SET @i = @i + 1
  END
将@i声明为INT
设置@i=1
而@i<3
开始
如果@i=1,则使用[DB1]
如果@i=2,则使用[DB2]
插入ThirdDB.dbo.ReportTable(字段)
选择前1个数字
来自CommonTable WITH(NOLOCK)
设置@i=@i+1
结束

我的初始测试表明它可以工作。

我建议不要使用循环。无论如何,您基本上都必须对每个数据库名称进行硬编码。一点动态sql可以大大减少这方面的工作量。此外,NOLOCK提示几乎总是一个坏主意。没有订单的上衣也是个坏主意。我从这个示例代码中删除了这两个

这里有几种方法可以利用动态sql实现这一点。第一个是生成单独的insert语句。第二个将生成一个包含UNION ALL的insert语句

declare @Prefix nvarchar(max) = 'INSERT INTO ThirdDB.dbo.ReportTable (field) SELECT MAX(SomeNumber) FROM '
    , @PostFix nvarchar(max) = '.dbo.CommonTable;'
    , @SQL nvarchar(max) = ''

select @SQL = @SQL + @Prefix + DBName + @PostFix
from
(
    values('DB1'),('DB2')
) Names(DBName)


select @SQL

--uncomment the line below when you are satisfied the query is correct
--exec sp_executesql @SQL
或者第二条路

declare @SQL nvarchar(max) = ''

select @SQL = @SQL + 'SELECT MAX(SomeNumber) From ' + Names.DBName + '.dbo.CommonTable union all '
from
(
    values('DB1'),('DB2')
) Names(DBName)


set @SQL = 'INSERT INTO ThirdDB.dbo.ReportTable (field) ' + left(@SQL, len(@SQL) - 10)

select @SQL

--uncomment the line below when you are satisfied the query is correct
--exec sp_executesql @SQL

它的伸缩性不好。如果你有很多数据库,你会得到很多If语句。您可以创建i和相应数据库的值的映射表,并使用它创建动态SQL语句。目标表使用3个参与方名称,而源表使用2个部分名称会令人困惑。到处泼洒nolock也不是一个好迹象。更好的方法是以某种方式使用动态sql并“查找”(例如,从元数据中选择)应该使用的数据库。在实例中的所有(或某些子集)数据库中运行查询的示例很容易找到。使用TOP而不使用order by子句通常是一个逻辑缺陷。您可以使用Powershell吗?也许是这样的?看看sp_foreachdb: