【发布时间】:2018-08-16 17:28:52
【问题描述】:
我几天前问过这个问题,但它涉及更深层次的答案,所以建议我创建一个全新的,所以就这样......
免责声明:我无法创建任何自定义 DB 对象(函数、SP、视图等),因此所有内容都需要内嵌在 SQL 查询中。
我正在查询审核表,为简单起见,该表具有以下字段:
AttributeMask
ChangedData
CreatedOn
ObjectId
数据库中的每条记录可能有多个与之关联的审计记录。每次对 DB 记录进行更改时,它都会在 Audit 表中创建一个记录,其中包含特定的 ObjectID 指向源记录 CreatedOn 将具有更改的 DateTime AttributeMask执行 SAVE 时已更改的 AttributeId 列表(注意,可能同时更改了多个字段),ChangedData 实际上将包含已更改的数据(预更改的值)。一个字段当然可以多次更改,如果是这种情况,该字段的多个审核记录将存在(不同的CreatedOn 值)。我需要查找源记录中的某些(不是全部)字段在特定日期的样子。
我可以在下面运行查询:
select a1.ChangeData as ChangedData1, a1.AttributeMask as AttributeMask2, a2.ChangeData as ChangedData2, a2.AttributeMask as AttributeMask2
from Table1 t
join audit a1 on a1.AuditId =
(select top 1 a.auditid from audit a where a.objecttypecode = 3
and a.objectid = T.ObjectId
and a.AttributeMask like '%,10192,%'
and a.CreatedOn <= '8-16-2018'
order by a1.CreatedOn desc)
join audit a2 on a2.AuditId =
(select top 1 a.auditid from audit a where a.objecttypecode = 3
and a.objectid = T.ObjectId
and a.AttributeMask like '%,10501,%'
and a.CreatedOn <= '8-16-2018'
order by a1.CreatedOn desc)
where t.ObjectID = SomeGuidValue
此查询正在查找在 8-16-2018 之前发生的 2 个字段(10192 和 10501)的最新更改。它返回以下数据(我添加了第三条记录来说明所有可能的情况):
ChangeData1 AttributeMask1 ChangeData2 AttributeMask2
NULL NULL True~~True~1904~~~15.8700000000~4760~30000~590~12000~0~390~1904~False~200~ ,10499,10604,10501,10436,10491,10490,10459,10099,10319,10253,10433,10031,10091,10020,10265,10008,10509,
~True~5.56~~House~~200000~ ,10030,10432,10435,197,10099,10192,198, False~1170~600~0~Complete~True~1770~ ,10501,10091,10008,10020,10570,10499,10253,10715,
~~~~200001~ ,10432,10435,197,10099,10192,198, True~2~True~~0~~~100.0000000000~1~business,96838c4f-e63c-e011-9a14-78e7d1644f78~~0~~~~0~False~~1~ ,10499,10509,10501,10203,10436,10491,10490,10459,10099,10157,10253,10433,10715,10031,10091,10020,10265,10008,10319,10699,
这意味着第一条记录仅更改为10501 字段,第二条记录仅更改为10192,第三条记录更改10192 和10501 字段。
AttributeMask 字段具有所有已更改的 FieldID 的逗号分隔列表(请注意,它以逗号开头和结尾)。
ChangedData 字段具有tilde (~) 分隔的已更改数据列表。 AttributeMask 中的每个条目对应于 ChangedData 中的条目。例如,如果我想查看第一条记录的 10501 字段中有哪些数据,我需要确定 AttributeMask 字段中的条目 #10501 (列表中的 #3),然后我需要找到找出ChangedData 字段中条目#3 中的数据(它是TRUE),如果我想查看字段10192 的第二条记录中的内容,我会看看它在AttributeMask 中有什么索引(它是# 6) 其对应的ChangedData字段值为2000000。
我需要以某种方式在同一个查询中提取这些数据。我得到了一些samples 的帮助,了解了如何做到这一点,但我一开始没有提出正确的问题(认为这比解释所有这些更简单)。
我需要这个查询返回是这样的:
ChangeData1 AttributeMask1 ChangeData2 AttributeMask2
NULL NULL TRUE 10501
200000 10192 FALSE 10501
200001 10192 TRUE 10501
我希望现在清楚了。
【问题讨论】:
-
看起来您在最后 2 段中写作真的很无聊。为什么需要将#3 解码为 ChangedData 中的#6?即使在那种情况下,您为什么还要将#5作为#6?无论如何,这看起来像一个糟糕的设计,我会尝试在客户端处理它而不是尝试使用 T-SQL(可能是一个 CLR 函数,但你说你不能在那里做任何事情——尽管它也是通过T-SQL)
-
嗨@Cetin Basoz,你是对的(不是我无聊)。我写错了。我纠正了它。设计并不是那么糟糕,只是不是为了由 T-SQL 解析而设计的。用任何计算机语言(例如 C#)解析都很容易。我只能创建一个查询。我无法在此数据库中创建任何其他内容(函数、SP、视图)。
-
如果
AttributeMask1包含两个值(2相同)会发生什么?最大连接数是多少? 名称编号总是暗示设计不佳。为什么不将Data和Mask与列表中的行计数器一起返回?如果这个列表可能越来越广泛,那就太奇怪了...... -
嗨@Shnugo,如果 AttributeMask1 包含这两个值,那很好,因为我一次只关心 1 个连接,所以我只为该特定连接提取值,另一个值将是另一个值的一部分加入。因此,可以通过不同的联接多次提取相同的审计记录。我不确定最大连接数,但我会说大约 15 个。我不会在真正的查询中使用名称编号。我打算让这些名称更具解释性。我不确定返回行计数器将如何解决我的问题?