【问题标题】:SQL - Dynamically selecting information into a variable from different databasesSQL - 从不同的数据库中动态选择信息到变量中
【发布时间】:2021-08-25 17:25:35
【问题描述】:

我有 3 个数据库,db 1 和 db 2 用于作业,db 3 用于工作流。

db 1 和 2 都有一个直接在 db 3 中创建工作流的过程。

我在 db 3 中有一个触发器,它在创建工作流时激活,因为我需要将更多信息从作业添加到工作流中。

所以我所做的是创建一个变量,我使用从 db 1 中的正常选择设置(从 db1.dbo.job 中选择作业)

我想知道是否有办法动态执行 select 语句 例如: 如果 db1 则 @db = db1 如果 db2 则 @db = db2

然后在@variable = select job from @db

现在我有以下查询,但我很简单地将我的所有逻辑添加到另一个 IF,然后更改选择语句...我不想这样做,因为我将添加更多数据库以与 db3 集成

Declare
@flag int,
@variable varchar(10)

set @flag = 1

if @flag = 1 
begin
    set @variable = (select job from db1.dbo.job)
end
else if @flag = 2 
begin
    set @variable = (select job from db2.dbo.job)
end

update db3 set job = @variable

有没有可能做我想做的事????

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    为此,您需要动态 SQL。

    注意:

    • 始终使用QUOTENAME 正确转义名称
    • 使用sp_executesql 在参数中传递数据。你也可以使用OUTPUT参数
    Declare
    @flag int
    
    set @flag = 1
    
    DECLARE @sql nvarchar(max) = N'
    UPDATE db3
    SET job = (
      SELECT TOP 1 job
      FROM ' + QUOTENAME(CASE WHEN @flag = 1 THEN 'db1' ELSE 'db2' END) + '.dbo.job
    );
    ';
    
    EXEC sp_executesql @sql;
    

    【讨论】:

      【解决方案2】:

      使用动态 sql 和 sp_executesql 等技术或动态创建同义词可以实现这种情况。

      但是,您对这种方法有一个更根本的问题。

      当调用触发器时,您不能假设inserted 表中只有一行,因为可以一次将多行插入到表中。

      为了演示这个问题,这里有一个“解决方案”来解决你的问题,如果只有一行插入到表T 中,它就会“有效”。但是想想如果插入多于一行会发生什么。如果使用不同的flag 值插入多行,那么“正确的”flag 值是什么?如果多行受到影响,我们如何根据@id 变量的值更新T 中的行?

      您可以使用此模式并使用游标遍历inserted 表中的行,但这会有点难看。

      create table T(id int, flag int, extraData nvarchar(128));
      
      create or alter trigger T_ins on T for insert as
      begin
         declare @sql nvarchar(max) = 'update T set extraData = (select top 1 name from {otherDB}.sys.tables) where id = @id'
      
         declare @db sysname, @id int;
      
         -- this select doesn't make any sense if more than one row exists in the inserted table!
         select   @id = id, 
                  @db = iif(inserted.flag = 1, 'master', 'msdb') 
         from     inserted;
      
         set @sql = replace(@sql, '{otherDB}', @db);
         exec sp_executesql  @sql, N'@id int', @id;
      end
      

      一种不使用游标的方法是左连接到其他数据库中所有可能的附加数据源,包括连接条件中的互斥标志值,并将列合并到更新语句中。我认为代码也更干净:

      create or alter trigger jobs_ins on jobs for insert as
      begin
         update      j
         set         extraData = coalesce(j1.somedata, j2.somedata)
         from        jobs j
         join        inserted ins on ins.id = j.id
         left join   otherDB1.dbo.jobdata j1 on i.flag = 1 and j1.id = ins.id
         left join   otherDB2.dbo.jobdata j2 on i.flag = 2 and j2.id = ins.id;
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-21
        • 1970-01-01
        • 2022-01-16
        • 2021-04-04
        • 2011-12-01
        • 1970-01-01
        • 2012-09-24
        • 1970-01-01
        相关资源
        最近更新 更多