2017-10-09 149 views
0

這是我們的xml文件的一部分。Xquery獲取位置()

   <point distanceTotal="162" seqNo="189"> 
       <lineSection id="395" track="1" direction="1"> 
       <outInfos> 
        <comment commentTypeId="4" priority="1"oneLiner="BOT"> 
         <layerVPK seasonValue="S0"/> 
         <vectors> 
          <vector dateFrom="2016-12-11"/> 
         </vectors> 
         <frenchText>1x3 MH</frenchText> 
        </comment> 
        <comment commentTypeId="4" priority="1" oneLiner="bot"> 
         <layerVPK seasonValue="S0"/> 
         <frenchText>Réception voie occupée</frenchText> 
         <dutchText>Test</dutchText> 
        </comment> 
       </outInfos> 
      </point> 

我們上傳到SqlServer列和XQuery我們正在獲取值。 但是,我找不到獲取位置()編碼的方法,基本上T-SQL ROW_NUMBER或密集等級不能用作不是所有數據都存在。 作爲例如dutchText只存在於第二個評論,也沒有現場標識2條評論....

這是SQL代碼

SELECT fi.file_uid, 
     fi.file_date, 
     T1.ref.value('@id',   'varchar(100)') AS gTV_id, 
     T2.ref.value('@id',   'varchar(100)') AS gTrn_id, 
     T4.ref.value('@seqNo',  'varchar(100)') AS gTrnTPp_seqNo, 
     T7.ref.value('text()[1]',  'varchar(1000)') AS gTrnTPpOiCDT_Text, 
     T6.ref.query('/globalTrainVariant/trains/globalTrainVariant/train/timetablePoints/point/outInfos/comment[position()]') AS Test 
    FROM ods.filesin fi 
     CROSS APPLY fi.file_xml.nodes('declare namespace cern="http://..."; 
             (/cern:trains/globalTrainVariant)') T1(ref) 
     CROSS APPLY T1.ref.nodes('declare namespace cern="http://..."; 
            (train)') T2(ref) 
     CROSS APPLY T2.ref.nodes('declare namespace cern="http://..."; 
           (timetablePoints)') T3(ref) 
     CROSS APPLY T3.ref.nodes('declare namespace cern="http://..."; 
            (point)') T4(ref) 
     CROSS APPLY T4.ref.nodes('declare namespace cern="http://..."; 
            (outInfos)') T5(ref) 
     CROSS APPLY T5.ref.nodes('declare namespace cern="http://..."; 
            (comment)') T6(ref) 
     CROSS APPLY T6.ref.nodes('declare namespace cern="http://..."; 
            (dutchText)') T7(ref) 
    WHERE fi.file_type = 'trains' 

的代碼沒有給出錯誤,但測試字段總是空白。

有什麼建議嗎?

+0

我不認爲位置函數是這樣工作的。此外,顯然不會正確返回位置,因爲您正在嘗試使用T6中的路徑。什麼_might_爲你工作是一個用row_number()和一個外部申請而不是交叉申請T7(ref)獲得正確的行號,然後排除那些其中t7.ref爲空的子查詢 – ZLK

回答

0

如果你想查找的documentation,你會看到,截至目前,您不能返回position()功能,直接的結果:

在SQL Server中,FN:位置()只能在 上下文相關謂詞的上下文中使用。具體來說,它只能在 括號([])內使用。

但是,有一個巧妙的技巧,你可以用它來獲得它。也就是說,您可以將元素的位置與已知序列進行比較,然後從該序列中返回匹配的值。下面的例子說明了這一點。

declare @x xml = N'<point distanceTotal="162" seqNo="189"> 
    <outInfos> 
    <comment commentTypeId="4" priority="1" oneLiner="BOT"> 
     <layerVPK seasonValue="S0" /> 
     <vectors> 
     <vector dateFrom="2016-12-11" /> 
     </vectors> 
     <frenchText>1x3 MH</frenchText> 
    </comment> 
    <comment commentTypeId="4" priority="1" oneLiner="bot"> 
     <layerVPK seasonValue="S0" /> 
     <frenchText>Réception voie occupée</frenchText> 
     <dutchText>Test</dutchText> 
    </comment> 
    </outInfos> 
</point>'; 

with cte as (
    select top (1000) row_number() over(order by ac.object_id) as [RN] 
    from sys.all_columns ac 
) 
select t.c.query('.') as [OutInfos], sq.RN as [TextPosition], x.c.query('.') as [DutchComment] 
from @x.nodes('/point/outInfos') t(c) 
    cross join cte sq 
    cross apply t.c.nodes('./comment[position() = sql:column("sq.RN")]/dutchText') x(c); 

在這裏面,CTE產生一組有序整數(我通常把一個特殊的表周圍,但你總是可以構建一個爲你去),並匹配條件的XQuery表達式定義指定輸出爲x(c)

+0

偉大的,用我可以做它的工作.... –

+0

對於搜索類似的人,這裏是最後的查詢... –

+0

SELECT ... T7.ref.value('text()[1]','varchar(1000)') AS gTrnTPpOiCDT_Text, xRows1.RN AS gTrnTPpOiC_seqNo,xRows2.RN AS gTrnTPpOiCDT_seqNo ... CROSS APPLY ods.RowNumbers_5 xRows1 CROSS APPLY T5.ref.nodes(「月......」;(。/'comment'position()= sql:column(「xRows1.RN」)])')T6(ref) CROSS APPLY ods.RowNumbers_1 xRows2 CROSS APPLY T6.ref.nodes('dec ...「;(。/dutchText [position()= sql:column(「xRows2.RN」)])')T7(ref) WHERE fi.file_type ='trains' –

0

我同意Roger所說的position()功能不能直接調用,應該在[]內。但是,這並不需要任何額外的表,並通過使用遞歸支持任意數量的行的解決方案:

declare @Xml xml = N'<?xml version="1.0" encoding="utf-16"?> 
<root> 
    <n>1</n> 
    <n>10</n> 
    <n>5</n> 
    <n>3</n> 
    <n>11</n> 
</root>'; 

with cte as 
(
    select t.c.value(N'n[1]', N'int') n, 1 RowNum 
    from @Xml.nodes(N'root[1]') t(c) 
    where t.c.exist(N'n[1]') = 1 
    union all 
    select t.c.value(N'n[position() = sql:column("cte.RowNum") + 1][1]', N'int') n, cte.RowNum + 1 
    from @Xml.nodes(N'root[1]') t(c) 
    cross join cte 
    where t.c.exist(N'n[position() = sql:column("cte.RowNum") + 1]') = 1 
) 
select * 
from cte; 
0

這可能是簡單,性能更好的才能算前面的//註釋使用Node Order Comparison Operators XML樹中的節點。

我沒有測試過龐大的XML文檔,但它絕對不是I/O密集型的,並且對我的設計測試的CPU密集度更低。

declare @x xml = N'<point distanceTotal="162" seqNo="189"> 
    <outInfos> 
    <comment commentTypeId="4" priority="1" oneLiner="BOT"> 
     <layerVPK seasonValue="S0" /> 
     <vectors> 
     <vector dateFrom="2016-12-11" /> 
     </vectors> 
     <frenchText>1x3 MH</frenchText> 
    </comment> 
    <comment commentTypeId="4" priority="1" oneLiner="bot"> 
     <layerVPK seasonValue="S0" /> 
     <frenchText>Réception voie occupée</frenchText> 
     <dutchText>Test</dutchText> 
    </comment> 
    </outInfos> 
</point>'; 

select 
    [OutInfos] = t.c.query('../..'), 
    [TextPosition] = t.c.value('let $dutchText := . return count(../../comment[. << $dutchText])', 'int'), 
    [DutchComment] = t.c.query('.') 
from @x.nodes('/point/outInfos/comment/dutchText') t(c)