几天前我问了这个问题,但是它涉及到更深的答案,因此有人建议我创建一个全新的问题,所以就这样...
免责声明:我无法创建任何自定义DB对象(函数,SP,视图等),因此所有内容都需要在SQL查询中内联。
我正在查询Audit表,为简化此问题,该表具有以下字段:
AttributeMask
ChangedData
CreatedOn
ObjectId
一个数据库中的每个记录可能有多个与之关联的审核记录。每次对数据库记录进行更改时,它将在Audit表中创建一条记录,其中包含特定的ObjectID
指向源记录,CreatedOn
的{{1}}为更改,DateTime
带有在执行SAVE时已更改的AttributeId的列表(注意,一次可能有多个字段被更改),而AttributeMask
实际上将具有已更改(预先更改)的数据值)。一个字段当然可以多次更改,并且在这种情况下,将存在该字段的多个审核记录(不同的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
之前发生的2个字段(10192
和10501
)的最新更改。它返回以下数据(我添加了第3条记录以说明所有可能的情况):
8-16-2018
这意味着第一条记录仅更改为字段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
字段。
AttributeMask字段包含所有已更改的FieldID的逗号分隔列表(请注意,它以逗号开头和结尾)。
ChangedData字段具有10501
(〜)分隔的已更改数据列表。 tilde
中的每个条目都对应于AttributeMask
中的条目。例如,如果我想查看第一条记录中10501字段中的数据,则需要确定#ChangedData
字段中的条目10501
(列表中的#3),然后我将需要找出AttributeMask
字段(ChangedData
)中条目#3中的数据,如果我想查看字段TRUE
的第二条记录中的内容,我会看到什么它在10192
中的索引(它是#6),在AttributeMask
字段中的对应值是ChangedData
。
我需要以某种方式在同一查询中提取此数据。 samples帮助我解决了如何完成此工作,但一开始我没有提出正确的问题(这比解释所有这些问题要容易得多)。
我需要此查询返回的内容如下:
2000000
我希望现在已经清楚了。
答案 0 :(得分:1)
如我的评论所述,您最好处理一个集合,然后使用具有 name-numbered 列的越来越多的列表进行处理。
尝试以如下模型表的格式提供初始输入集:
有一个正在运行的ID,您的ObjectID,您要查找的代码以及两个字符串。我插入了您提供的数据,但没有并排:
DECLARE @tbl TABLE(ID INT IDENTITY, CodeId INT,ObjectId INT, ChangeData VARCHAR(1000), AttributeMask VARCHAR(1000));
INSERT INTO @tbl VALUES
(10192,1,NULL,NULL)
,(10501,1,'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,')
,(10192,2,'~True~5.56~~House~~200000~',',10030,10432,10435,197,10099,10192,198,')
,(10501,2,'False~1170~600~0~Complete~True~1770~',',10501,10091,10008,10020,10570,10499,10253,10715,')
,(10192,3, '~~~~200001~',',10432,10435,197,10099,10192,198,')
,(10501,3,'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,');
-查询会将字符串转换为XML,以便通过其位置索引将其插入
-然后将所有代码提取并编号为派生列表。
-根据找到的位置取相应的值
SELECT t.ID
,t.ObjectId
,t.CodeId
,t.ChangeData
,t.AttributeMask
,Casted.ValueXml.value('/x[sql:column("PartIndex")][1]','nvarchar(max)') ValueAtCode
FROM @tbl t
CROSS APPLY
(
SELECT CAST('<x>' + REPLACE(t.AttributeMask,',','</x><x>') + '</x>' AS XML).query('/x[text()]') AS CodeXml
,CAST('<x>' + REPLACE(t.ChangeData,'~','</x><x>') + '</x>' AS XML) AS ValueXml
) Casted
CROSS APPLY(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PartIndex
,x.value('text()[1]','nvarchar(max)') AS CodePart
FROM Casted.CodeXml.nodes('/x') A(x)
) CodeDerived
WHERE CodeDerived.CodePart=t.CodeId;
结果
ID ObjectId CodeId ValueAtCode
2 1 10501 True
3 2 10192
4 2 10501 False
5 3 10192 200001
6 3 10501 True
但是这会很糟糕...
您的整个方法不是基于集合的。以下内容未经测试,我没有您的数据库,但将指向基于集合的解决方案。
DECLARE @Codes TABLE(CodeID INT);
INSERT INTO @Codes VALUES(10192),(10501);
select t.SomeIdOfYourMainTable
,c.CodeID
,a1.ChangeData
,a1.AttributeMask
from Table1 t
CROSS JOIN @Codes c --will repeat the result for each value in @Codes
CROSS APPLY
(
select top 1 a.ChangeData
,a.AttributeMask
from [audit] a
where a.objecttypecode = 3
and a.objectid = t.ObjectId
and a.AttributeMask like CONCAT('%,',c.CodeID,',%')
and a.CreatedOn <= '20180816' --use culture independant format!!!
order by a.CreatedOn desc
) a1;
这允许您插入任意数量的代码(无需重复任何连接),并且将返回与我上面的示例类似的集合。
如果您需要进一步的帮助:请关闭此问题,然后使用完全正常运行的独立MCVE来开始新的问题,以重制您的案子。