动态SQL更新一个表格多个表格?

时间:2017-06-06 12:25:48

标签: sql sql-server dynamic-sql

我有一个表PI_Catalogue_Update,它将Schema Name,Table Name,Count(*)作为Volume和max(ETLRunTime)存储为来自多个原始表的LastUpdate。如何构建一个查询,该查询将使用PI_Catalogue_Update中的SchemaName和TableName并查询原始表,并在每次运行SP时更新卷和LastUpdate。

可能我需要一些动态SQL。我仍然无法弄明白该怎么做。

表格如下:

SchemaName      TableName   Volume     LastUpdate
ProdInsights_In abc         4680816    2017-06-04 00:00:00.000
ProdInsights_In bcd         52250      2017-06-04 00:00:00.000
ProdInsights_In def         744225     2017-06-04 00:00:00.000
ProdInsights_In gih         668502     2017-06-04 00:00:00.000

我写的查询是另一种方法,我创建了一个原始表格的视图,[ProdInsights_In]。[View_Table_Catalogue] .View看起来像:

CREATE VIEW  [ProdInsights_In].[View_Table_Catalogue] AS
select
  'ProdInsights_In' as SchemaName
  ,'abc' as TableName
  ,Count(*) Volume
  ,MAX(ETLRunTime) as LastUpdate
From [ProdInsights_In].[abc]
Union All
select
  'ProdInsights_In' as SchemaName
  ,'bcd' as TableName
  ,Count(*) Volume
  ,MAX(ETLRunTime) as LastUpdate
From [ProdInsights_In].[bcd]
Union All ....

然后我使用以下SP从View中更新PI_Catalogue_Update表。 程序如下:

MERGE
INTO    [dbo].[PI_Project_Catalogue] t1
USING   [ProdInsights_In].[View_Table_Catalogue] t2
ON      t1.SchemaName = t2.SchemaName
    and t1.TableName = t2.TableName
WHEN MATCHED THEN
UPDATE
SET     t1.Volume = t2.Volume
       ,t1.LastUpdate = t2.LastUpdate
WHEN NOT MATCHED THEN
INSERT  (SchemaName, TableName, Volume, LastUpdate)
VALUES  (t2.SchemaName. t2.TableName, t2.Volume, t2.LastUpdate)

1 个答案:

答案 0 :(得分:2)

您可以避免使用动态sql并使用系统视图来获取行计数,而不是为每个表执行select count(*) from ...

select 
    [SchemaName]= s.name
  , [TableName] = o.name
  , [row_count] = p.rows
from sys.partitions p
  inner join sys.indexes i 
    on p.object_id = i.object_id
      and p.index_id = i.index_id
      and i.index_id < 2
  inner join sys.objects o
    on i.object_id = o.object_id
  inner join sys.schemas s
    on o.schema_id = s.schema_id
where o.is_ms_shipped=0

作为更新:

update picu
    set [Volume] = p.rows
      , [LastUpdate] = sysutcdatetime()
from sys.partitions p
  inner join sys.indexes i 
    on p.object_id = i.object_id
      and p.index_id = i.index_id
      and i.index_id < 2
  inner join sys.objects o
    on i.object_id = o.object_id
  inner join sys.schemas s
    on o.schema_id = s.schema_id
  inner join PI_Catalogue_Update picu
    on picu.SchemaName = s.name
   and picu.TableName  = o.name

参考:

使用临时表和循环来获取max(ETLRunTime)以使用动态sql进行更新:

/* --- get all tables and row count that have `ETLRunDate` column. --- */
create table #tmp (
    id int not null identity(1,1)
  , SchemaName sysname collate Latin1_General_CI_AS -- set collation to match collation of `pi_Project_Catalogue` 
  , TableName  sysname collate Latin1_General_CI_AS
  , Volume bigint
  , LastUpdate date
);
insert into #tmp (SchemaName, TableName, Volume)
select 
    [SchemaName]= s.name
  , [TableName] = o.name
  , [Volume] = p.rows
from sys.partitions p
  inner join sys.indexes i 
    on p.object_id = i.object_id
      and p.index_id = i.index_id
      and i.index_id < 2
  inner join sys.objects o on i.object_id = o.object_id
  inner join sys.schemas s on o.schema_id = s.schema_id
where o.is_ms_shipped=0
  and exists (
    select 1
    from sys.columns c
    where c.object_id = o.object_id
      and c.name = 'ETLRunTime'
      )
/* --- loop --- */      
declare @c   bigint = (select max(id) from #tmp);
declare @id  bigint = 1;
declare @sql nvarchar(4000);
declare @params nvarchar(32) = N'@id bigint';
while @id <= @c
begin;
  select @sql = N'
    update #tmp 
      set LastUpdate = (
        select max(ETLRunTime)
        from '+quotename(SchemaName)+'.'+quotename(TableName)+'
      )
    where id = @id;'
  from #tmp where id = @id
  exec sp_executesql @sql, @params, @id;
set @id = @id+1;
end;
/* --- merge --- */
merge into [dbo].[pi_Project_Catalogue] with (holdlock) as tar 
using #tmp as src
  on tar.SchemaName = src.SchemaName
 and tar.TableName  = src.TableName
when matched then update 
  set tar.Volume     = src.Volume
    , tar.LastUpdate = src.LastUpdate
when not matched then insert (SchemaName, TableName, Volume, LastUpdate)
  values (src.SchemaName, src.TableName, src.Volume, src.LastUpdate);

您可以使用单独的语句进行更新,然后插入,而不是您使用的merge。我使用merge,因为这是您在问题中的内容,添加了with (holdlock)

rextester演示:http://rextester.com/HCOLM75894

返回:

+------------+-----------+--------+---------------------+
| SchemaName | TableName | Volume |     LastUpdate      |
+------------+-----------+--------+---------------------+
| dbo        | a         |      1 | 01.01.2017 00:00:00 |
| dbo        | c         |      2 | 06.06.2017 00:00:00 |
| dbo        | d         |      3 | 06.06.2017 00:00:00 |
+------------+-----------+--------+---------------------+

使用这个虚拟数据:

create table pi_Project_Catalogue (SchemaName sysname collate Latin1_General_CI_AS, TableName sysname collate Latin1_General_CI_AS, Volume bigint, LastUpdate date)
create table a (id int not null identity(1,1) primary key clustered, ETLRunTime date)
insert into  a values ('20170101');
create table b (id int not null identity(1,1) ); -- no ETLRunTime  column
insert into  b default values
create table c (id int not null identity(1,1), ETLRunTime date );
insert into  c values (sysutcdatetime()),(sysutcdatetime());
create table d (id int not null identity(1,1), ETLRunTime date );
insert into  d values (sysutcdatetime()),(sysutcdatetime()),(sysutcdatetime());

merge参考: