2017-03-14 13 views
0

私は、ストアドプロシージャからスカラーUDFを呼び出してカラム値を取得しています。スカラーUDFの中にはxmlがあり、特定のノードのカンマ区切り値を取得する必要があります。私はクロス適用を使用しましたが、ストアドプロシージャが実際にレポートを取得するために使用されるため、パフォーマンスのボトルネックが大きくなりました。SQLでxmlからコンマ区切り値を取得

フィールドID、BookingID(複製可能)、FareDetailsを持つテーブル[Traveler]があります。 FareDetailsの内部にはxmlが格納されています。

UDF内部のロジックが次のとおりです。 第一ソリューション、クロスApplyを使用する:

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、 になります。2)BookingIDが一意でない(2回来る)場合、FareDetail xmlが次のようになると、出力は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> 

それは心の中でパフォーマンスを維持行うことができる方法を提案してください。

+0

? 'mysql'、' postgresql'、 'sql-server'、' oracle'、 'db2'のどれかを指定するタグを追加してください。 –

答えて

0

これは完全に動作する例です。

あなたは私たちに言った、そのパフォーマンスの問題ですので、スカラーUDFを使用しないでください!

それはcreate a (reduced!!!) 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 

- この機能であるそれは(何BEGIN...ENDas tableを返していないし、完全にインライン化された)

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 [email protected] 
    FOR XML PATH('') 
),1,1,'') AS BookingInfoCSV; 
GO 

- ヒントXQuery data() functionのトリックは、値に空白が含まれていると壊れます!

Booking -tableからSELECTの呼び出しすべての行以下--Theとは、フィッティングの詳細

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

アップ--clean(実際のデータで気をつけを取得します! RDBMSはこのです

USE master; 
GO 
DROP DATABASE testDB; 

--The結果

BookingID SomeBookingData BookingInfoCSV 
1   Booking 1  AP,AP,XY,MN 
2   Booking 2  AA,BB 
+0

Hey @ Shnugo、 の値が にある場合を除き、このソリューションはうまくいきます。e xmlがこのように来る場合 AP 2つのノードがある場合は AP、AP、 を修正してください。 –

+0

コード内にスペース*がない場合は、結果を 'REPLACE(A.BookingInfoCSV、 ',,'、 '、')'で囲むだけで、ダブルカンマを単一カンマで置き換えることができます。正直言って:これは(良い)ハックですが、それはハックです... – Shnugo

+0

ホラ@ shnugo ..しかし、値が(APの後のスペース) AP私たちはAPとして出てくるよ、 –

関連する問題