2017-06-06 84 views
1

我有一个PI_Catalogue_Update表,它将多个原始表中的架构名称,表名,Count(*)存储为Volume和Max(ETLRunTime)作为LastUpdate。如何构建一个查询,该查询将使用PI_Catalogue_Update中的SchemaName和TableName,并查询原始表,并在每次运行SP时更新卷和LastUpdate。动态SQL更新一个表格形式多表?

可能我需要一些动态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从视图更新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) 
+0

我建议你使用触发器,而不是动态查询https://docs.microsoft.com/en -us/sql/t-sql/statements/create-trigger-transact-sql –

+0

您能否发布您迄今为止撰写的查询? –

+0

我用我的代码编辑了问题部分。谢谢。 – DataPsycho

回答

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)使用TEMPORA RY表和循环使用动态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参考:

+0

嗨,这是一个很好的方式。但sysutcdatetime()总是显示当前日期时间,即使我没有更新某个表的任何内容。实际上,我有一个工具,每天在这些表中插入数据,并在工具更新的所有表中为名为ETLRunTime的列。我想把'Max(ETLRunTime)'作为LastUpdate可能的一些方法呢? 我已经编辑了我写过的查询的问题,但查询看起来不够好并且效率不错。谢谢 – DataPsycho

+0

@DataPoliceInc。更新我的答案以包含“ETLRunTime”。不知何故,当我第一次读这个问题时就错过了。 – SqlZim

+0

嗨,这是一个很好的方式。真的很感谢你的努力。我学到了一些新东西。谢谢.. – DataPsycho