从 SQL 中的 xml 获取逗号分隔值

2024-03-01

我从存储过程调用标量 UDF 来获取列值。在标量 UDF 中,我有一个 xml,并且必须获取特定节点的逗号分隔值。我使用了Cross apply,但它造成了巨大的性能瓶颈,因为存储过程实际上是用来获取报告的。

有一个表[Traveler],其中包含字段ID、BookingID(可以重复)和FareDetails。我们在 FareDetails 中存储 xml。

UDF内部逻辑如下: 第一个解决方案,使用交叉应用:

 ALTER FUNCTION [dbo].[GetBookingInfo] (@BookingID bigint, @InfoID smallint) RETURNS VARCHAR(1024) AS
        BEGIN
            DECLARE @InfoCSV VARCHAR(1024)

            --
            -- Fare Basis: InfoID = 1
            --
            IF @InfoID = 1
            BEGIN

                    SELECT @InfoCSV = (SELECT
                        (PTSD.PSTDNode.value('(FBC)[1]', 'VARCHAR(1024)')  + ',') [text()]
                    FROM
                        [Traveler]
                        CROSS APPLY [FareDetails].nodes('/AirFareInfo/PTSDPFS/PTSD') PTSD(PSTDNode)
                    WHERE
                        [BookingID] = @BookingID
                    ORDER BY
                        ID ASC
                    FOR XML PATH (''))

                IF @InfoCSV IS NOT NULL AND LEN(@InfoCSV) > 0
                    SET @InfoCSV = LEFT(@InfoCSV, LEN(@InfoCSV) - 1)
            END

            RETURN @InfoCSV

第二种解决方案,无需交叉应用:

  ALTER FUNCTION [dbo].[GetBookingInfo] (@BookingID bigint, @InfoID smallint) RETURNS VARCHAR(1024) AS
        BEGIN
            DECLARE @InfoCSV VARCHAR(1024)

            --
            -- Fare Basis: InfoID = 1
            --
            IF @InfoID = 1
            BEGIN

                  SELECT @InfoCSV = (SELECT TOP 1 REPLACE(FareDetails.query(N'data(/AirFareInfo/PTSDPFS/PTSD/FBC)').value('(text())[1]','nvarchar(100)'),' ',',')
        FROM [Traveler]
        WHERE
                [BookingID] = @BookingID)

                IF @InfoCSV IS NOT NULL AND LEN(@InfoCSV) > 0
                    SET @InfoCSV = LEFT(@InfoCSV, LEN(@InfoCSV) - 1)
            END

            RETURN @InfoCSV

第二种解决方案可以节省大量时间,但是当我们有重复的预订 ID 时,它不会连接 FBC 的所有值。 例如: 1)如果 BookingID 是唯一的,并且我们有如下的 FareDetail xml,那么输出应该是 AP,AP 2)如果 BookingID 不唯一(出现两次),并且我们有如下的 FareDetail xml,则输出应该是与两个 BookingID 相对应的 AP,AP,AP,AP。 xml如下:

<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
  <PT>Flight</PT>
  <FPMID>0</FPMID>
  <PTID>1</PTID>
  <FS>
    <CID>2</CID>
    <Value>0</Value>
  </FS>
  <TF>
    <CID xsi:nil="true" />
    <Value>0</Value>
  </TF>
  <VF>
    <CID>2</CID>
    <Value>0</Value>
  </VF>
  <VD>
    <CID>2</CID>
    <Value>0</Value>
  </VD>
  <VCR xsi:nil="true" />
  <VC>
    <CID>2</CID>
    <Value>0</Value>
  </VC>
  <VFC>
    <CID>2</CID>
    <Value>0</Value>
  </VFC>
  <VST />
  <VIT />
  <AAPFVDR xsi:nil="true" />
  <CC>
    <CID>2</CID>
    <Value>0</Value>
  </CC>
  <D>
    <CID>2</CID>
    <Value>514.15</Value>
  </D>
  <PD>
    <CID>2</CID>
    <Value>0</Value>
  </PD>
  <EBF>
    <CID>2</CID>
    <Value>0</Value>
  </EBF>
  <CST>
    <DL>
      <ATRID>13</ATRID>
      <OB>
        <CID>2</CID>
        <Value>74.04</Value>
      </OB>
      <OC>
        <CID>2</CID>
        <Value>0.00</Value>
      </OC>
      <OS>
        <CID>2</CID>
        <Value>0.00</Value>
      </OS>
      <OF>
        <CID>2</CID>
        <Value>50.83</Value>
      </OF>
      <OP>
        <CID>2</CID>
        <Value>0.00</Value>
      </OP>
      <C>
        <CID>2</CID>
        <Value>0</Value>
      </C>
      <IBF>false</IBF>
      <D>2014-06-09T14:57:53.521Z</D>
    </DL>
  </CST>
  <CIT />
  <CRMR xsi:nil="true" />
  <CRM>
    <CID>2</CID>
    <Value>0</Value>
  </CRM>
  <TL ATC="Tax" PC="" DEN="User Development Fee - Arrival (UDF)">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>75.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="Passenger Service Fee">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>146.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="User Development Fee - Departure (UDF)">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>1681.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="Cute Fee">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>50.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="Government Service Tax">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>151.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="User Development Fee - Arrival (UDF)">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>833.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="Passenger Service Fee">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>1132.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="User Development Fee - Departure (UDF)">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>76.00</Value>
    </Amount>
  </TL>
  <TL ATC="Tax" PC="" DEN="Government Service Tax">
    <TID xsi:nil="true" />
    <Amount>
      <CID>2</CID>
      <Value>148.00</Value>
    </Amount>
  </TL>
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>AP</FBC>
      <ACD RBD="" ACCID="1" MCT="Super Sale Fare(AP)" INC="false" />
      <ATSID xsi:nil="true" />
    </PTSD>
  </PTSDPFS>
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>AP</FBC>
      <ACD RBD="" ACCID="1" MCT="Super Sale Fare(AP)" INC="false" />
      <ATSID xsi:nil="true" />
    </PTSD>
  </PTSDPFS>
  <RuleDetails>
    <TRS xsi:nil="true" />
    <PP xsi:nil="true" />
    <II xsi:nil="true" />
    <LTD xsi:nil="true" />
  </RuleDetails>
</AirFareInfo>

请建议如何在考虑性能的情况下完成此操作。


这是一个完全有效的示例。

您告诉我们,性能很重要,所以不要使用标量 UDF!

像这样尝试一下(下次你的工作就是创建一个 (减少了!!!) MCVE https://stackoverflow.com/help/mcve:

CREATE DATABASE testDB;
GO
USE testDB;
GO
CREATE TABLE Booking(BookingID INT CONSTRAINT PK_Booking PRIMARY KEY
                    ,SomeBookingData VARCHAR(100));
INSERT INTO Booking VALUES(1,'Booking 1'),(2,'Booking 2');

CREATE TABLE BookingInfo(BookingID INT CONSTRAINT FK_BookingInfo_BookingID FOREIGN KEY REFERENCES Booking(BookingID)
                        ,SomeOtherInfo VARCHAR(100)
                        ,FareDetails XML);
INSERT INTO BookingInfo VALUES
 (1,'First row for ID=1, returns AP,AP'
 ,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>AP</FBC>
    </PTSD>
  </PTSDPFS>
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>AP</FBC>
    </PTSD>
  </PTSDPFS>
</AirFareInfo>')
,(1,'Second row for ID=1, returns XY,MN'
 ,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>XY</FBC>
    </PTSD>
  </PTSDPFS>
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>MN</FBC>
    </PTSD>
  </PTSDPFS>
</AirFareInfo>')
,(2,'row with ID=2, returns AA,BB'
 ,N'<AirFareInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" IPFA="false">
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>AA</FBC>
    </PTSD>
  </PTSDPFS>
  <PTSDPFS>
    <PTSD IO="false">
      <FBC>BB</FBC>
    </PTSD>
  </PTSDPFS>
</AirFareInfo>');
GO

——这就是功能。它返回as table并且是完全内联的(没有BEGIN...END!)

CREATE FUNCTION dbo.CreateBookingInfoCSV(@BookingID INT)
RETURNS TABLE
AS
RETURN
SELECT STUFF(
(
    SELECT ','+REPLACE(FareDetails.query(N'data(/AirFareInfo/PTSDPFS/PTSD/FBC)').value(N'.',N'nvarchar(max)'),' ',',')
    FROM BookingInfo AS bi
    WHERE bi.BookingID=@BookingID
    FOR XML PATH('')
),1,1,'') AS BookingInfoCSV;
GO

--Hint技巧与XQuery data() function如果您的值包含空格,将会中断!

- 下列SELECT调用所有行Booking-表并获取配件详细信息

SELECT b.BookingID
      ,b.SomeBookingData
      ,A.BookingInfoCSV 
FROM Booking AS b
OUTER APPLY dbo.CreateBookingInfoCSV(b.BookingID) AS A;
GO

- 清理 (小心真实数据!)

USE master;
GO
DROP DATABASE testDB;

- 结果

BookingID   SomeBookingData BookingInfoCSV
1           Booking 1       AP,AP,XY,MN
2           Booking 2       AA,BB
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 SQL 中的 xml 获取逗号分隔值 的相关文章

随机推荐

  • “IconDefinition”类型的参数不可分配给“IconDefinitionOrPack”类型的参数

    我在用着Angular 6 角度启动器 https github com gdi2290 angular starter和fontawesome 跟随here https github com FortAwesome angular fon
  • 并行运行多个 R 函数

    我有一个数据集 其中包含很少的数字列和超过 1 亿行的 data table 对象 我想根据其他列对某些列进行分组操作 例如 对 d 列中每个类别的 a 列的唯一元素进行计数 my data a count uniqueN col a co
  • 即使在 Monitor.Enter 之后,Monitor.TryEnter 也始终返回 true

    我想我错过了一些关于正确行为的事情Monitor Enter and Monitor TryEnter 这是我编写的一段代码 用于将问题与其余代码分开 object lockObj new object bool result Monito
  • 用于大型数据集的 sqlite 或 mysql

    我正在处理大型数据集 数十百万条记录 有时是数百百万条记录 并且想要使用与 R 良好链接的数据库程序 我正在尝试在 mysql 和 sqlite 之间做出决定 数据是静态的 但我需要做很多查询 In this 链接到 sqlite 帮助 h
  • Mongodb NoRM 和 POCO

    我正在 C 中试验 Mongodb 和 NoRM 根据我的阅读 唯一标识 Mongodb 中文档的 ObjectId 是一种 特殊 Guid 从某种意义上来说是唯一的 但其中有一些重要的部分 可以更轻松地进行排序和索引 时间戳 机器哈希 p
  • 如何处理“AES/GCM/NoPadding”的 IV 和身份验证标签?

    我在用着AES GCM NoPaddingJava 8 中的加密 我想知道我的代码是否存在安全缺陷 我的代码似乎work 因为它加密和解密文本 但一些细节尚不清楚 我的主要问题是 Cipher cipher Cipher getInstan
  • 谷歌地图 API 3 + WMS

    有人可以给我最好的主意 如何将 WMS 图层放在 Google 地图上 我有很多图层和很多样式 我在 StackOverflow 研究了很多问答 但我没有明白如何管理多种样式和图层 我想放入我的 JQuery 代码中 这里有一个很好的例子
  • CryptEncrypt 不加密整个文本

    我正在尝试使用 wincrypt 加密短信 然而我的代码是不可预测的 它不会加密 解密整个明文 而只会加密 解密其中的一部分 如果我更改密码的长度 例如更改为 password123 它会加密 解密不同数量的字符 这是我的代码 includ
  • 如何获得国家名称

    我使用下面的代码来获取文化类型列表 有没有办法只获取国家 地区名称 谢谢 static void Main string args StringBuilder sb new StringBuilder foreach CultureInfo
  • socket.gaierror: [Errno -2] Python3 未知名称或服务

    我正在尝试使用端口扫描程序 import socket import subprocess import sys from datetime import datetime subprocess call clear shell True
  • 如何在 ASP.NET Core 中使用 JWT 授权重定向到 401 登录页面

    我的 Startup cs 中有这个 JWT 授权配置 services AddAuthentication opts gt opts DefaultAuthenticateScheme JwtBearerDefaults Authenti
  • 拉伸链接引导程序实用程序在 Chrome 中不起作用

    看来拉伸链接 https getbootstrap com docs 4 4 utilities stretched link 在 Bootstrap 中不适用于 tr Firefox 可以 但 Chrome 不行 Chrome 似乎忽略了
  • Powershell - 使用共享证书添加 SSL 绑定

    我正在使用以下代码将证书链接到我添加的 SSL 绑定 thumb Get ChildItem cert LocalMachine My where object Subject like wildCardSubject Select Obj
  • bash / shell 脚本中增加时间(分钟和秒)

    我需要在变量中增加分钟和秒 相对于时间 首先 我不确定声明 时间 变量是否写为 time 00 00 00 or time date 00 00 00 从那里 我想将该变量增加 10 分钟和秒 结果是01 00 00 增加至01 10 10
  • 尝试在 C 中执行 strcat 函数时 EXC_BAD_ACCESS

    我有一个用 C 语言为 uni 编写的程序 当我的代码到达这一行时 strcat md5 blah 我收到 EXC BAD ACCESS 错误 并且我的应用程序崩溃了 据我所知 它没有任何问题 所以我认为一双新的眼睛可能会解决我的问题 有任
  • Google fit API:如何获取活动期间所走路线的地图?

    我正在使用 Google Fit API 开发健身应用程序 看看这张 Google Fit 应用程序上记录的 Google Fit 训练的图片 here https i stack imgur com q2ykP png 我想知道是否可以将
  • 内部字符串、字符串池和永久空间上的垃圾收集

    在探索了 java 的字符串内部结构之后 我对所谓的 永久空间 感到困惑 我最初的理解是它持有String literals以及类元数据 如中所述这个问题 https stackoverflow com questions 1279449
  • Pandas 数据透视表中缺少值?

    我有一个数据集 如下所示 student question answer number Bob How many donuts in a dozen A 1 Sally How many donuts in a dozen C 1 Edwa
  • python 使用逗号交换值会引起混乱

    这涉及到我在尝试解决链表反向问题时遇到的一个问题 首先放一些链表定义和生成链表的快速方法的初步代码 class ListNode def init self x self val x self next None def repr self
  • 从 SQL 中的 xml 获取逗号分隔值

    我从存储过程调用标量 UDF 来获取列值 在标量 UDF 中 我有一个 xml 并且必须获取特定节点的逗号分隔值 我使用了Cross apply 但它造成了巨大的性能瓶颈 因为存储过程实际上是用来获取报告的 有一个表 Traveler 其中