SQL Unpivot、交叉应用、动态查询?
Posted
技术标签:
【中文标题】SQL Unpivot、交叉应用、动态查询?【英文标题】:SQL Unpivot, Cross Apply, Dynamic Query? 【发布时间】:2018-04-24 17:43:04 【问题描述】:我正处于十字路口。有人可以帮我...送我走正确的道路。
我想比较/呈现来自 2 个数据库表的数据,如下所示:
应用程序数据库:许多表都有将更新/删除更改(审计)复制到另一个数据库的触发器。
审核数据库:从应用程序数据库中的触发器复制的信息
我想要做的应该是相当简单的。下面是我想要比较数据以了解所做更改的可视化。
我有一个带有CROSS APPLY
和UNIONS
的工作版本(它很长,并且为列、表等手动输入很糟糕)。这些列不是动态的,这使得数百行代码变得粗暴且难以管理。必须有一个更优雅的设计。请有任何想法。
我只需要从两个表中返回一个特定的行 (ID),以进行比较。
APP DB
colA colB colC colD
1 hello foo date
APP Audit DB
colA colB colC colD
1 hi bar date
这是要输出的内容:
colA_data ColumnName oldData newData
1 colB hi hello
1 colC bar foo
1 colD date date
我希望我已经理解了我想要完成的事情。
我想动态读取列名(不难),然后出于报告原因将结果并排放置。显然匹配列并将它们放入行中。
非常感谢示例代码。
【问题讨论】:
【参考方案1】:可能最简单的方法是使用UNPIVOT
:
1。静态版
这里只是介绍UNPIVOT
的使用,这是一个简单的静态版本,应该可以解决你的问题:
declare @appDB table( [colA] int, [colB] nvarchar(50),[colC] nvarchar(50),[colD] nvarchar(50))
declare @auditDB table( [colA] int, [colB] nvarchar(50),[colC] nvarchar(50),[colD] nvarchar(50))
insert into @appDB select 1,'hello', 'foo', 'date'
insert into @auditDB select 1,'hi', 'bar', 'date'
select old.ColA_data, old.ColumnName, old.OldData, new.NewData
from(
select o.colA as ColA_data, o.ColumnName, o.OldData
from @auditDB s
unpivot ([OldData] for [ColumnName] in ([colB], [colC], [colD])) o
) OLD
inner join
(
select n.colA as ColA_data, n.ColumnName, n.NewData
from @appDB t
unpivot ([NewData] for [ColumnName] in ([colB], [colC], [colD])) n
) NEW
on new.ColA_data = old.ColA_data and new.ColumnName = old.ColumnName
结果:
2。动态版
现在是完整版。您可以使用动态 SQL 更改从 SQL Server INFORMATION_SCHEMA
元数据中检索它们的列。
请注意,在此示例中,我添加了一个新列 (ColE
)
if OBJECT_ID('appDB') is not null drop table appDB
if OBJECT_ID('auditDB') is not null drop table auditDB
create table appDB (colA int, colB nvarchar(50),colC nvarchar(50),colD nvarchar(50),colE nvarchar(50))
create table auditDB(colA int, colB nvarchar(50),colC nvarchar(50),colD nvarchar(50),colE nvarchar(50))
insert into appDB select 1,'hello', 'foo', 'date','time'
insert into auditDB select 1,'hi', 'bar', 'date','time'
declare @cols nvarchar(max)='' --this variable holds all the dates that will become column names
declare @sql nvarchar(max)='' --this variable contains the TSQL dinamically generated
select @cols = @cols + ', [' +COLUMN_NAME + ']'
from INFORMATION_SCHEMA.COLUMNS
where TABLE_NAME='appDB'
and COLUMN_NAME <>'colA'
set @cols = RIGHT(@cols, len(@cols)-2)
set @sql= @sql + ' select old.ColA_data, old.ColumnName, old.OldData, new.NewData '
set @sql= @sql + ' from('
set @sql= @sql + ' select o.colA as ColA_data, o.ColumnName, o.OldData'
set @sql= @sql + ' from auditDB s '
set @sql= @sql + ' unpivot ([OldData] for [ColumnName] in ('+@cols+')) o'
set @sql= @sql + ' ) OLD'
set @sql= @sql + ' inner join'
set @sql= @sql + ' ('
set @sql= @sql + ' select n.colA as ColA_data, n.ColumnName, n.NewData'
set @sql= @sql + ' from appDB t '
set @sql= @sql + ' unpivot ([NewData] for [ColumnName] in ('+@cols+')) n'
set @sql= @sql + ' ) NEW'
set @sql= @sql + ' on new.ColA_data = old.ColA_data and new.ColumnName = old.ColumnName'
exec(@sql)
结果:
【讨论】:
以上是关于SQL Unpivot、交叉应用、动态查询?的主要内容,如果未能解决你的问题,请参考以下文章
PL/SQL Oracle :- 在传递值时动态 UNPIVOT ORACLE TABLE