将 UNION 视图重写为动态视图

发布于 2024-10-17 09:12:54 字数 1182 浏览 3 评论 0原文

我已经为此工作了几天,但找不到合适的解决方案,希望有人能提供帮助。

我们有几个结构相同的数据库服务器(SQL Server),通过链接服务器连接。我们有一堆跨所有服务器联合数据的视图:

CREATE VIEW Things_view AS
  SELECT id, thing
    FROM server1.database1.dbo.stuff
  UNION ALL
  SELECT id, thing
    FROM server2.database2.dbo.stuff
  UNION ALL
  SELECT id, thing
    FROM server3.database3.dbo.stuff

这有几个问题:

  • 当我们添加服务器时,我们必须修改 意见。
  • 我们的开发环境需要 相同数量的数据库和假链接 服务器,以便我们可以安装这些 意见。
  • 有些服务器没有 包括来自其他一些服务器的数据。今天,我们通过这些服务器上的自定义视图来做到这一点,但这是一个部署噩梦。

所以我希望动态地重写它。目标是:

  • 允许开发环境 包含不同数量的数据库。他们很可能 一台服务器上有 2 个或更多数据库。
  • 为每个服务器提供一种方法 指定哪些其他服务器 包括在结果中。
  • 最小化复杂性,以便 解决方案仍然有些 可维护。
  • 创建一种解决方案 源代码受控并用于所有 服务器。

最重要的是:

  • 将其公开为具有相同内容的视图 名称,这样我们就不必重写我们的 整个应用程序。

当然,我不能在视图或函数中执行动态 SQL。我尝试将其重写为存储过程,然后使用 OPENROWSET技巧从视图查询存储过程。这不起作用,因为我必须使用数据库名称完全限定过程,这将需要更多动态 SQL(因为数据库名称不同)。然后我考虑在主数据库上使用同义词,但这违反了维护和源代码控制目标。

我完全可以创建一个包含服务器名称和数据库名称以及包含标志(如果需要)的新表。事实上,这是理想的,因为它集中了每个环境的配置。

我对此完全困惑不解,现在我向互联网求助,请求帮助!

I've been working on this for days and I can't find a proper solution, I'm hoping someone can help.

We have several database servers (SQL Server) with identical structures, connected by linked servers. We have a bunch of views that union data across all the servers:

CREATE VIEW Things_view AS
  SELECT id, thing
    FROM server1.database1.dbo.stuff
  UNION ALL
  SELECT id, thing
    FROM server2.database2.dbo.stuff
  UNION ALL
  SELECT id, thing
    FROM server3.database3.dbo.stuff

There are several problems with this:

  • When we add servers, we have to modify
    views.
  • Our development environments need
    the same number of databases and fake linked
    servers so we can install these
    views.
  • Some of the servers do not
    include
    data from some of the other servers. Today we do this with customized views on those servers but that's a deployment nightmare.

So I was hoping to rewrite this dynamically. The goals are:

  • Allow development environments to
    contain a different number of databases. They are likely to
    have 2 or more databases on a single server.
  • Provide a way for each server to
    specify which other servers to
    include in the results.
  • Minimize the complexity so the
    solution remains somewhat
    maintainable.
  • Create one solution that can be
    source controlled and used on all
    servers.

And most importantly:

  • Expose it as a view with the same
    name so we don't have to rewrite our
    entire application.

Of course, I can't do dynamic SQL in a view or function. I tried rewriting this as a stored procedure, then using the OPENROWSET trick to query the stored proc from a view. That didn't work because I had to fully qualify the proc with the database name, which would require more dynamic SQL (because the database names are different). Then I thought about fooling around with synonyms on the master database but that violates the maintenance and source control goals.

I'm perfectly OK with creating a new table with server names and database names and inclusion flags if needed. In fact, that is ideal because it centralizes the configuration for each environment.

I've been completely baffled by this and now I'm reaching out to you, Internet, in a last-ditch plea for help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不知在何时 2024-10-24 09:12:54

一种可能的解决方案是创建一个调整视图的存储过程。例如(未经测试):

create procedure dbo.RecreateView
as
declare @sql varchar(max)

select @sql = IsNull(@sql + 'union all ','') +
              'select * from ' + name + '.dbo.YourView '
from   sys.databases
where  name like 'DbNamePrefix%'

set @sql = 'create view dbo.YourView as ' + @sql
exec (@sql)

您可以在添加数据库后调用存储过程,甚至可以从计划任务中调用存储过程。

One possible solution is to create a stored procedure that adjusts the view. For example (not tested):

create procedure dbo.RecreateView
as
declare @sql varchar(max)

select @sql = IsNull(@sql + 'union all ','') +
              'select * from ' + name + '.dbo.YourView '
from   sys.databases
where  name like 'DbNamePrefix%'

set @sql = 'create view dbo.YourView as ' + @sql
exec (@sql)

You could then call the stored procedure after you add a database, or even from a scheduled task.

我喜欢麦丽素 2024-10-24 09:12:54

如果您使用最新的 SQL Server,使用 Synonym 将是一个不错的选择

Using Synonym would be a good option if you are using latest SQL server

从此见与不见 2024-10-24 09:12:54

如果您有一个跟踪服务器和数据库的表,您可以在该表的触发器中动态构建视图。

看看这个对另一个问题的回答。它建议同样的事情,并有一些示例代码来更改触发器中的视图定义。

动态表设计(通用查找表),需要一个很好的查询来获取值

它可能适合你。

If you have a table keeping track of servers and databases you could build the view dynamically in a trigger on that table.

Look at this answer to another question. It suggests the same thing and has some sample code to alter a view definition in a trigger.

Dynamic table design (common lookup table), need a nice query to get the values

It might work for you.

夜光 2024-10-24 09:12:54

这是我的建议。创建一个表来存储特定服务器上每个视图的配置。
然后根据这些配置编写动态sql来创建视图脚本。
然后在服务器上运行查看脚本。
当您想要添加新服务器时,请将其添加到配置表中,该配置表可以有一个触发器来自动为正在更改的视图重新创建脚本。或者从表中重新创建脚本并运行它们成为每个部署的标准部分。

Here is what I'd suggest. Create a table to store the configuration for each view on the particular server.
Then write dynamic sql to create the view script based on those configurations.
Then run the view script on the server.
When you want to add a new server, add it to the configurationtable which could have a trigger to automatically recreate the scripts for the views that are being changed. Or have recreating scripts from the table and running them be a standard part of every deployment.

从来不烧饼 2024-10-24 09:12:54

这听起来像是数据仓库的工作... http://en.wikipedia.org/wiki/Data_warehouse 您需要它按设定的时间表运行,这样数据就不是实时的。这是唯一的缺点。

使用类似于下面的文件从每个 server[n].database.tablename 加载数据。

--Here is how you would administer the script.  One single script that you would only need to modify when you added/removed servers.
So you can easily add this to source control or whatever. You can also do all this, without linked servers, if you look at some ETL tools. like SSIS

insert into dataserver1.datawarehouse.tablename select *,'svr1,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr2,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr3,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr4,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr5,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr6,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr7,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr8,'db','tablename' from svr1.db.tablename

所以你需要创建许多插入语句。您拥有的每个服务器/数据库/表组合都有一个。

insert into dataserver1.datawarehouse.tablename select *,'svr1,'db','tablename' from svr1.db.tablename

因此,当您将数据加载到这个新的数据库表中时,您只需附加到每一行原始服务器名/数据库名/表名所以......你的数据看起来像这样

col1 col2 col3 srvnam dbname tbl
foo  bar  some MSSQL1 master mycooltable
foo  bar  some MSSQL2 other  mycooltable

现在,你所要做的就是查询一个表,它会非常快,而且干净。

This sounds like a job for a data warehouse... http://en.wikipedia.org/wiki/Data_warehouse You would need this to run at a set schedule so the data would not be realtime. That is the only downside.

Load data from each server[n].database.tablename using a file similar to the one below.

--Here is how you would administer the script.  One single script that you would only need to modify when you added/removed servers.
So you can easily add this to source control or whatever. You can also do all this, without linked servers, if you look at some ETL tools. like SSIS

insert into dataserver1.datawarehouse.tablename select *,'svr1,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr2,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr3,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr4,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr5,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr6,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr7,'db','tablename' from svr1.db.tablename
insert into dataserver1.datawarehouse.tablename select *,'svr8,'db','tablename' from svr1.db.tablename

So you are required to create many insert statements. One for each server/db/table combo you have.

insert into dataserver1.datawarehouse.tablename select *,'svr1,'db','tablename' from svr1.db.tablename

So as you load the data into this new database table, you will simply append to every row the original servername/databasename/tablename SO.... Your data looks like this

col1 col2 col3 srvnam dbname tbl
foo  bar  some MSSQL1 master mycooltable
foo  bar  some MSSQL2 other  mycooltable

Now, all you have to do is query off of one table, it will be really fast, and clean.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文