簡體   English   中英

SQL-獲取數組中特定元素的值

[英]SQL - Get value for a specific element in array

我幾天前問了這個問題,但涉及的答案要深一些,因此有人建議我創建一個全新的問題,所以就這樣...

免責聲明 :我無法創建任何自定義DB對象(函數,SP,視圖等),因此所有內容都需要在SQL查詢中內聯。

我正在查詢審核表,為簡化此問題,它具有以下字段:

AttributeMask
ChangedData
CreatedOn
ObjectId

一個數據庫中的每個記錄可能有多個與之關聯的審核記錄。 每次對數據庫記錄進行更改時,它將在Audit表中創建一個記錄,該記錄具有指向源記錄的特定ObjectIDCreatedOn將具有更改的DateTimeAttributeMask帶有已更改的AttributeId的列表當執行SAVE(注意,可能一次更改了多個字段)時, 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個字段( 1019210501 )的最新更改。 它返回以下數據(我添加了第3條記錄以說明所有可能的情況):

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,

這意味着第一個記錄已更改field 10501只,第二記錄已更改為10192只,三記錄有變化既1019210501領域。

AttributeMask字段包含所有已更改的FieldID的逗號分隔列表(請注意,它以逗號開頭和結尾)。 ChangedData字段以tilde (〜)分隔已更改數據的列表。 AttributeMask每個條目都對應於ChangedData條目。 例如,如果我想查看第一條記錄中10501字段中的數據,則需要確定AttributeMask字段中的哪些條目# 10501 (在列表中為#3),然后我需要找出哪些數據是在ChangedData字段的條目#3中(它是TRUE ),如果我想查看字段10192第二條記錄中的內容,我會看到它在AttributeMask (它的#6)中具有什么索引,並且它在ChangedData字段中的對應值為2000000 我需要以某種方式在同一查詢中提取此數據。 有人為我提供了一些有關如何完成此操作的示例 ,但我一開始未能提出正確的問題(認為這比解釋所有這些都更簡單)。

我需要此查詢返回的內容是這樣的:

ChangeData1 AttributeMask1  ChangeData2 AttributeMask2
NULL    NULL    TRUE    10501
200000  10192   FALSE   10501
200001  10192   TRUE    10501

我希望現在已經清楚了。

如我的評論所述,最好處理一個集合,然后處理越來越多的具有名稱編號列的列表。

嘗試以類似於以下模型表的格式提供初始輸入集:

有一個正在運行的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

但這將是無聊的...

UPDATE

您的整個方法不是基於集合的 以下內容未經測試,我沒有您的數據庫,但將指向基於集合的解決方案。

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重新開始一個新問題,以重現您的案子。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM