使用 T-SQL 查询 XML 节点得到错误的结果集
Posted
技术标签:
【中文标题】使用 T-SQL 查询 XML 节点得到错误的结果集【英文标题】:Querying XML nodes using T-SQL getting wrong result set 【发布时间】:2022-01-18 04:16:31 【问题描述】:我正在尝试从 XML 文件中提取记录,但我得到的记录不符合 WHERE 子句中的条件。
这是我的 T-SQL 代码:
DECLARE @StartLossDate date = '2018-12-15';
DECLARE @EndLossDate date = CONVERT(date,GETDATE());
SELECT @StartLossDate as StartLossDate, @EndLossDate as EndLossDate;
-- Get result set.
SELECT DISTINCT t.SysDate, t.PolicySysID, t.PolicyNo
a.b.value('(LossDt)[1]','date') as LossDate
, a.b.value('(ClaimNumber)[1]','varchar(max)') as ClaimNumber
, d.e.value('(LossTypeCd)[1]','varchar(max)') as LossTypeCd
FROM #tempXMLRecords t
CROSS APPLY t.xmlPlus.nodes('ISO/PassportSvcRs/Reports/Report/ReportData/ISO/PassportSvcRs/PassportInqRs/Match/Claim/Loss') as a(b)
CROSS APPLY t.xmlPlus.nodes('ISO/PassportSvcRs/Reports/Report/ReportData/ISO/PassportSvcRs/PassportInqRs/Match/Claim/Payment') as d(e)
WHERE a.b.value('(LossDt)[1]','date') BETWEEN @StartLossDate AND @EndLossDate
AND d.e.value('(LossTypeCd)[1]','varchar(4)') = 'TOWL'
ORDER BY PolicySysID asc;
我得到的结果是:
上述 TOP 2 记录在 XML 中没有 TOWL 的 LossTypeCd。
任何帮助/指导将不胜感激。我想我对 CROSS APPLY 中的节点定义应该如何工作感到困惑。
这是我的 XML:
<ISO>
<PassportSvcRs>
<Reports>
<Report>
<ReportData>
<ISO>
<PassportSvcRs>
<PassportInqRs>
<Match>
<Claim>
<Loss>
<LossDt>2020-11-01</LossDt>
<ClaimNumber>7842198101J20110105</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2020-10-28</LossDt>
<ClaimNumber>7842198101J20102805</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2020-10-03</LossDt>
<ClaimNumber>7842198101J20100305</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2019-10-21</LossDt>
<ClaimNumber>66203023279998</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>3963</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2019-05-26</LossDt>
<ClaimNumber>PTX19035829</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COMP</CoverageCd>
<LossTypeCd>COMP</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2018-10-16</LossDt>
<ClaimNumber>0522909605</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>UM</CoverageCd>
<LossTypeCd>UM</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-11-05</LossDt>
<ClaimNumber>0481373215</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>23</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-10-07</LossDt>
<ClaimNumber>0478275043</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>2866</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>RENT</CoverageCd>
<LossTypeCd>RENT</LossTypeCd>
<ClaimStatusCd>W</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-06-09</LossDt>
<ClaimNumber>JM177514</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>2374</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2016-01-16</LossDt>
<ClaimNumber>7842382435D16011605</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>4175</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>RENT</CoverageCd>
<LossTypeCd>RENT</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
</PassportInqRs>
</PassportSvcRs>
</ISO>
</ReportData>
</Report>
</Reports>
</PassportSvcRs>
</ISO>
谢谢。
【问题讨论】:
没有示例 XML,我们无法在此告诉您太多信息。提供minimal reproducible example。 我不相信该查询包含确保付款数据和损失数据属于同一索赔的逻辑。也许您需要先在 CROSS APPLY 中选择 Claim 节点,然后从选定的 Claims 中选择 Loss/LossDate、Loss/ClaimNumber 和 Payment/LossTypeCd。 @TN,谢谢。我会试试的。欣赏这个建议。如果您不介意看一下,我只是附上了 XML。谢谢。 提问时,您需要提供minimal reproducible example: (1) DDL 和样本数据填充,即 CREATE 表加上 INSERT T-SQL 语句。 (2) 你需要做什么,即逻辑和你的代码尝试在 T-SQL 中实现它。 (3) 期望的输出,基于上述#1 中的样本数据。 (4) 您的 SQL Server 版本 (SELECT @@version;)。全部在问题内,没有图片。 知道了。感谢@YitzhakKhabinsky。 【参考方案1】:我不认为该查询包含确保付款数据和损失数据属于同一索赔的逻辑。
查看新发布的 XML,我发现索赔可能包含多笔付款,但(显然)只有一笔损失。您可能需要一个交叉申请来选择索赔,然后第二次交叉申请来选择与每个索赔相关的付款。
以下精简查询似乎有效。
DECLARE @Xml XML = '...' -- See posted XML above
DECLARE @tempXMLRecords TABLE(xmlPlus XML)
INSERT @tempXMLRecords VALUES (@Xml)
SELECT
c.value('(Loss/LossDt)[1]','date') as LossDate
, c.value('(Loss/ClaimNumber)[1]','varchar(max)') as ClaimNumber
, p.value('(LossTypeCd)[1]','varchar(max)') as LossTypeCd
FROM @tempXMLRecords t
CROSS APPLY t.xmlPlus.nodes('ISO/PassportSvcRs/Reports/Report/ReportData/ISO/PassportSvcRs/PassportInqRs/Match/Claim') as C(c)
CROSS APPLY c.nodes('./Payment') as P(p)
ORDER BY 1,2,3
【讨论】:
您的建议正是我所做的。非常感谢您的时间和帮助。 好答案。根据 OP 的要求,您可能希望在第一个.nodes
中有一个谓词,例如 Match/Claim[Payment/LossTypeCd[text() = "TOWL"]]
。您可以只用c.nodes('Payment')
稍微缩短第二个。将/text()
添加到.value
函数将提高它们的性能。【参考方案2】:
请尝试以下解决方案。
它支持一次索赔的多次付款。
当它发生时,LossTypeCd 列将有多个声明。
如果您不需要,可以很容易地调整该列中只有一个声明。
SQL
DECLARE @tbl TABLE (ID INT IDENTITY PRIMARY KEY, xmlPlus XML);
INSERT INTO @tbl (xmlPlus) VALUES
(N'<?xml version="1.0"?>
<ISO>
<PassportSvcRs>
<Reports>
<Report>
<ReportData>
<ISO>
<PassportSvcRs>
<PassportInqRs>
<Match>
<Claim>
<Loss>
<LossDt>2020-11-01</LossDt>
<ClaimNumber>7842198101J20110105</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2020-10-28</LossDt>
<ClaimNumber>7842198101J20102805</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2020-10-03</LossDt>
<ClaimNumber>7842198101J20100305</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>78</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2019-10-21</LossDt>
<ClaimNumber>66203023279998</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>3963</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2019-05-26</LossDt>
<ClaimNumber>PTX19035829</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COMP</CoverageCd>
<LossTypeCd>COMP</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2018-10-16</LossDt>
<ClaimNumber>0522909605</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>UM</CoverageCd>
<LossTypeCd>UM</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-11-05</LossDt>
<ClaimNumber>0481373215</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>TOWL</CoverageCd>
<LossTypeCd>TOWL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>23</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-10-07</LossDt>
<ClaimNumber>0478275043</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>2866</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>RENT</CoverageCd>
<LossTypeCd>RENT</LossTypeCd>
<ClaimStatusCd>W</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2017-06-09</LossDt>
<ClaimNumber>JM177514</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>2374</LossPaymentAmt>
</Payment>
</Claim>
</Match>
<Match>
<Claim>
<Loss>
<LossDt>2016-01-16</LossDt>
<ClaimNumber>7842382435D16011605</ClaimNumber>
</Loss>
<Payment>
<CoverageCd>COLL</CoverageCd>
<LossTypeCd>COLL</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>4175</LossPaymentAmt>
</Payment>
<Payment>
<CoverageCd>RENT</CoverageCd>
<LossTypeCd>RENT</LossTypeCd>
<ClaimStatusCd>C</ClaimStatusCd>
<LossPaymentAmt>0</LossPaymentAmt>
</Payment>
</Claim>
</Match>
</PassportInqRs>
</PassportSvcRs>
</ISO>
</ReportData>
</Report>
</Reports>
</PassportSvcRs>
</ISO>');
-- DDL and sample data population, end
DECLARE @StartLossDate DATE = '2018-12-15'
, @EndLossDate DATE = CAST(GETDATE() AS DATE);
SELECT ID
, c.value('(Loss/LossDt/text())[1]', 'DATE') AS LossDate
, c.value('(Loss/ClaimNumber/text())[1]', 'VARCHAR(100)') AS ClaimNumber
, c.query('data(Payment/LossTypeCd)').value('.', 'VARCHAR(100)') AS LossTypeCd
FROM @tbl
CROSS APPLY xmlplus.nodes('/ISO/PassportSvcRs/Reports/Report/ReportData/ISO/PassportSvcRs/PassportInqRs/Match/Claim') AS t(c)
WHERE c.value('(Loss/LossDt/text())[1]', 'DATE') BETWEEN @StartLossDate AND @EndLossDate
AND c.exist('Payment/LossTypeCd[./text()="TOWL"]') = 1;
输出
+----+------------+---------------------+------------+
| ID | LossDate | ClaimNumber | LossTypeCd |
+----+------------+---------------------+------------+
| 1 | 2020-11-01 | 7842198101J20110105 | TOWL |
| 1 | 2020-10-28 | 7842198101J20102805 | TOWL |
| 1 | 2020-10-03 | 7842198101J20100305 | TOWL |
+----+------------+---------------------+------------+
【讨论】:
感谢您花时间发帖。感谢您的帮助。 @Melinda,您的最低分母是 Payment/LossTypeCd 吗?我为此使用了 ClaimNumber。 @DaleK,我做到了。谢谢 正如@TN 所建议的,Claim 是我使用的。我必须在 XML 中上一层才能获得所有相关数据。我不确定为什么我的问题是-1。我猜它没用(?)。 我认为它在您添加示例数据之前被否决了,并且投反对票的人可能还没有回来并看到您对其进行了改进。以上是关于使用 T-SQL 查询 XML 节点得到错误的结果集的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PL-SQL 查询包含 XML 的 Clob 节点
T-SQL XQuery (XML路径查询) (转)http://blog.csdn.net/Beirut/article/details/8150116