SQL-获取数组中特定元素的值
几天前我问了这个问题,但它涉及到一个更深层次的答案,所以有人建议我创建一个全新的,所以现在开始 免责声明:我无法创建任何自定义DB对象(函数、SP、视图等),因此所有内容都需要在SQL查询中联机 我正在查询审计表,为了简单起见,该表有以下字段:SQL-获取数组中特定元素的值,sql,tsql,Sql,Tsql,几天前我问了这个问题,但它涉及到一个更深层次的答案,所以有人建议我创建一个全新的,所以现在开始 免责声明:我无法创建任何自定义DB对象(函数、SP、视图等),因此所有内容都需要在SQL查询中联机 我正在查询审计表,为了简单起见,该表有以下字段: AttributeMask ChangedData CreatedOn ObjectId 数据库中的每条记录都可能有多条与之关联的审核记录。每次对DB记录进行更改时,它都会在审核表中创建一条记录,其中包含特定的ObjectID,该记录将指向源记录Cre
AttributeMask
ChangedData
CreatedOn
ObjectId
数据库中的每条记录都可能有多条与之关联的审核记录。每次对DB记录进行更改时,它都会在审核表中创建一条记录,其中包含特定的ObjectID
,该记录将指向源记录CreatedOn
,该记录将包含更改的DateTime
,AttributeMask
,其中包含在执行保存时已更改的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
这意味着第一条记录仅更改为字段10501
,第二条记录仅更改为10192
,第三条记录同时更改为10192
和10501
字段
AttributeMask字段具有以逗号分隔的已更改的所有字段ID列表(请注意,它以逗号开头和结尾)。
ChangedData字段具有波浪号(~)已更改数据的分隔列表。AttributeMask
中的每个条目对应于ChangedData
中的条目。例如,如果我想查看第一条记录中10501字段中的数据,我需要确定AttributeMask
字段中的条目是什么(它在列表中是第3个)然后我需要找出changedata
字段(它是TRUE
)中条目3中的数据,如果我想查看字段10192
的第二条记录中的数据,我会查看它在AttributeMask
中的索引(它是#6),它在changedata
字段中的对应值是200000
。
我需要在同一个查询中以某种方式提取这些数据。我得到了一些关于如何做到这一点的帮助,但我在开始时没有提出正确的问题(认为这比解释所有这些更简单)
我需要此查询返回如下内容:
ChangeData1 AttributeMask1 ChangeData2 AttributeMask2
NULL NULL TRUE 10501
200000 10192 FALSE 10501
200001 10192 TRUE 10501
我希望这一点现在已经很清楚了。正如我在评论中所说的那样,你最好先处理一个集合,然后再处理一个越来越广泛的列表,其中包含名称编号的列
尝试以如下模型表所示的格式提供初始输入集:
有一个正在运行的ID、您的ObjectID、您正在查找的代码以及这两个字符串。我插入了您提供的数据,但不是并排插入的:
--查询将把字符串转换为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;
但这会很慢
使现代化
您的整个方法不是基于集合的。以下内容完全未经测试,我没有您的数据库,但将指向基于集合的解决方案
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;
DECLARE@Codes表(CodeID INT);
插入@代码值(10192),(10501);
选择t.SomeIdOfYourMainTable
,c.CodeID
,a1.1更改数据
,a1.AttributeMask
来自表1 t
交叉连接@Codes c--将对@Codes中的每个值重复结果
交叉应用
(
选择Top1 a.ChangeData
,a.AttributeMask
来自[审计]a
其中a.objecttypecode=3
a.objectid=t.objectid
和a.AttributeMask-like-CONCAT(“%,”,c.CodeID,“,%”)
而且a.CreatedOn看起来你在最后两段的写作中真的很无聊。为什么需要在ChangedData中对#3进行解码以获得#6?即使如此,为什么你要以#5作为#6为例?无论如何,这看起来是一个糟糕的设计,我会尝试在客户端处理它,而不是尝试使用T-SQL(可能是CLR函数,但你是说你不能在那里做任何事情-尽管它也是通过t-SQL完成的)Hi@Cetin Basoz,你是对的(不是因为我觉得无聊)。我打错了。我改正了。设计并不是那么糟糕,只是不是为了用t-SQL解析。用任何计算机语言解析都很容易(例如C)。我只能创建一个查询。我无法在此数据库中创建任何其他内容(函数、SP、视图)。如果AttributeMask1
包含两个值(对于2
相同),该怎么办?最大连接数是多少?名称编号总是一个错误设计的提示。为什么不在列表中返回数据
和掩码
以及行计数器?如果这个列表可能越来越宽,这真的很奇怪…嗨@Shnugo如果AttributeMask1同时包含这两个值,那没关系,因为我只关心1个joi一次n,所以我将只提取该特定连接的值,而另一个值将是另一个连接的一部分。因此,可以通过不同的连接多次提取相同的审核记录。我不确定最大连接数,但我会说大约15。我不打算在实际查询中命名数字。我打算让名称更具解释性。我“我不确定返回行计数器将如何解决我的问题?嗨@Shnugo,这似乎可行,但我不知道如何解决:-)你到底在哪里指明了要查找的字段ID?它只返回10501和10192,但你的查询中到底有哪些字段ID?我问这个问题是因为我需要再查找大约10个字段ID。你是对的,它可能很慢,但我需要在更大的d上测试它的性能
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;