SQL 从 XML 中获取列的逗号分隔值

标签 sql sql-server temp-tables sqlxml cross-apply

我从存储过程调用标量 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

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>

输出应该是AP,AP

请建议更好的替代方案,因为调用 SP 具有此功能,10000 条记录需要 15 秒。

如果有帮助,我们将不胜感激。

最佳答案

不要使用标量函数,而是将此函数转换为内联表值函数并使用交叉应用之类的东西......

内联表值函数

CREATE FUNCTION [dbo].[GetBookingInfo_NEW] (@BookingID bigint) 
RETURNS TABLE 
AS
RETURN (

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

查询

Select t.ID 
     , t.BookingID 
     , REVERSE(STUFF(REVERSE(c.[FareDetails]), 1, 1, ''))
FROM [Traveler] t
CROSS APPLY [dbo].[GetBookingInfo_NEW](t.BookingID) c

关于SQL 从 XML 中获取列的逗号分隔值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42748860/

相关文章:

MySQL - 按多条记录分类的COUNT散点图

SQL - 加入存档表时避免完全扫描

sql - SSIS 表达式选取变量作为列然后抛出错误

php - mysql-php,创建临时表时出错

mysql - 避免对来自不同表的多列进行分组的临时表

mysql - 加快创建mysql表(from select)

sql - FETCH NEXT 到类似表的结构中

mysql - SQL IMDB 网站查询查找出演至少 10 部电影的 Actor

c# - 如何将 Count(*) 与 DAL2 一起使用?

mysql - MySql 中 SqlServer @@Error 的副本