在这个项目中,每个表都有一个“历史表”,它与原始表相同,但添加了以下列:[HistId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil] 基本上在每次插入,更新,删除时,我们都会像日志一样。之后,我们很容易看到用户做了什么,谁做了什么,什么时候做了。
看看它的外观,here
问题在于数据历史记录的显示方式。我看到它基本上是全部选择,所有内容都像excel电子表格一样显示。 很难找到改变的东西和不改变的东西。大多数情况下,更改一次只能进行一列。当你试图找到具体的东西时,很难看到你需要的信息。
我在考虑使用不同的方法。 我想只显示看起来像日志的内容中的内容。 (我也会在以后搜索这个)
它的样子:
Record with title "a" inserted by albert on 2010-01-01
Record's Title was updated from "a" to "b" by john on 2010-01-02
Record's Title was updated from "b" to "c" by dave on 2010-01-03
Record's Description was updated from "abc" to "def" by paul on 2010-01-04
...etc...
Record was deleted by bin on 2010-01-08
对于6日的变化(标题和描述),我想要有1条记录,无论是2条记录,哪条都不那么复杂。 所以基本上我正在寻找一种方法,从一组记录中显示只有变化的数据,没有别的
额外信息:
历史表的结构无法更改,因为有很多这样的表。
我只想改变检索数据的方式。
有20列以上的表格
有些表有3000万条记录,所以性能很重要,但通常不会显示太多数据,我会说最多50条记录)
在每一行都有“from”和“to”,看起来不错,但如果它太复杂,那么“to”就够了
答案 0 :(得分:1)
假设 i)无论出于何种原因,历史表都不会发生变化。
ii)因为你一次会显示50,100,150条记录。所以百万条记录不是问题。
试试这个让我知道,
create table #side ([Id] [int] IDENTITY NOT NULL,
[Title] [varchar](50) NOT NULL,
[Description] [varchar](250) NULL)
create table #h ([HistId] [int] IDENTITY(1,1) NOT NULL,
[Id] [int] NOT NULL,
[Title] [varchar](50) NOT NULL,
[Description] [varchar](250) NULL,
[TypeId] [int] NULL,
[ActionUser] [int] NULL,
[ActionCode] [char](1) NOT NULL,
[ActionDate] [datetime] NOT NULL,
[ValidUntil] [datetime] NULL)
insert into #side ([Title],[Description]) values ('a','abc')
insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'a','abc',123,991,'i','01/01/2010',NULL)
declare @mod datetime;
set @mod = '01/02/2010'
insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'b','abc',123,991,'u',@mod,NULL)
insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','abc',123,991,'u',@mod,NULL)
insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','def',123,991,'u',@mod,NULL)
insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'d','pqr',123,991,'u',@mod,NULL)
select * from #h order by HistId Desc
--select * from #side
select h.HistId, case when h.ActionCode='i' THEN
'Record with Title "'+h.title+'" inserted '
when h.ActionCode='u' THEN
'Records '+ case
when h.title<>h1.title and h.[Description]<>h1.[Description] then 'Title,Description was updated from
"'+h1.title+'","'+h1.[Description]+'" to " '+h.title+' " , "'+h.[Description]+'" respectively'
when h.title<>h1.title then 'Title was updated from "'+h1.title+'" to " '+h.title+' " '
when h.[Description]<>h1.[Description] then 'Description was updated from "'+h1.[Description]+'" to " '+h.[Description]+' " '
else '' end
when h.ActionCode='d' THEN
'Record was deleted'
else
null
END
+'by '+cast(h.ActionUser as varchar)+' on '+convert(varchar(10),h.actiondate ,120)+''
from #h h
left join #h h1
on h.HistId=(h1.HistId+1)
--left join #usertable u
--on u.userid=h.[ActionUser]
drop table #h
drop table #side
答案 1 :(得分:0)
这是一种简单的方法,它使用self-join将每条记录与之前的条目进行比较。该技术假设HistId
是一个完整的整数序列。
示例数据
/* Sample data.
* Three records are created.
* The first is a base line.
* The next two are updates.
* Update one contains one change.
* Update two contains two changes.
*
* See also: http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-query
*/
DECLARE @SampleHistory TABLE
(
HistoryId INT IDENTITY(1, 1),
Title VARCHAR(255),
[Description] VARCHAR(255)
)
INSERT INTO @SampleHistory
(
Title,
[Description]
)
VALUES
('Data Warehouse Toolkit', 'First Edition'), -- Base record.
('Data Warehouse Toolkit', 'Second Edition'), -- Description changed.
('The Data Warehouse Toolkit', 'Third Edition') -- Name and description changed.
;
<强>查询强>
/* Change detection, using self join.
* See also: https://msdn.microsoft.com/en-us/library/ms177490.aspx
*/
SELECT
CASE
WHEN h2.Title IS NULL THEN 'New Title: ' + h1.Title + '. '
WHEN h1.Title <> h2.Title THEN 'Title updated from ' + h2.Title + ' to ' + h1.Title + '. '
ELSE ''
END
+
CASE
WHEN h2.[Description] IS NULL THEN 'New Description: ' + h1.[Description] + '. '
WHEN h1.[Description] <> h2.Title THEN 'Description updated from ' + h2.[Description] + ' to ' + h1.[Description] + '. '
ELSE ''
END
FROM
@SampleHistory AS h1
LEFT OUTER JOIN @SampleHistory AS h2 ON h2.HistoryId = (h1.HistoryId - 1)
;
这种方法的缺点是你必须为每个历史表中的每个字段编写一个case表达式。不好。避免所有这种输入的一种方法是使用dynamic SQL。但这可能很复杂!
最后的想法
我不认为SQL非常适合这样的任务。由于其基于集合的性质,循环字段和有条件地返回值需要花费很多精力。在C#,Java等中,你可以用更少的努力获得相同的结果。
对于所有版本,SQL Server 2016包含Change Data Capture开箱即用。 CDC包含在SQL Server 2008,2012和2014 Enterprise和Developer版本中。在可能的情况;我更喜欢使用本机功能。手动解决方案需要管理,并且通常缺乏开发人员添加的高级功能。