交叉应用 returns 行过多

Cross apply returns too many rows

DDL:

CREATE TABLE [testXML]
(
    [scheduleid] [uniqueidentifier] primary key,
    [XMLData1] [xml] NULL
)

INSERT INTO testXML ([scheduleid],XMLData1) 
VALUES ('88888888-DDDD-4444-AAAA-666666666666','<ArrayOfRDData xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <RDData  h="Title"  o="2017-11-02T16:00:00Z" p="212" q="000000cb-0000-0000-0000-000000000000" an="203"  >
    <rps>
      <rp s="00a566e2-0000-0000-0000-000000000000"  ag="1" i="0" j="0" ah="2018-01-10T17:00:00Z" >
        <piData programId="00a566e2-0000-0000-0000-000000000000" al="0" />
        <res>
          <re o="2018-01-10T17:00:00Z"  p="212" q="000000cb-0000-0000-0000-000000000000" >
            <riData av="false"  az="201" />
          </re>
        </res>
      </rp>
      <rp s="00a5860a-0000-0000-0000-000000000000" ag="1" i="0" j="0" ah="2018-01-26T17:00:00Z" >
        <piData programId="00a5860a-0000-0000-0000-000000000000" al="1" />
        <res>
          <re o="2018-01-26T17:00:00Z"  p="212" q="000000cb-0000-0000-0000-000000000000" >
            <riData av="false"  az="201" />
          </re>
        </res>
      </rp>
      <rp s="00a595c4-0000-0000-0000-000000000000" ag="0" i="0" j="0" ah="2018-01-31T17:00:00Z" >
        <piData programId="00a595c4-0000-0000-0000-000000000000" al="2"  />
        <res>
          <re o="2018-01-31T17:00:00Z"  p="212" q="000000cb-0000-0000-0000-000000000000"  />
        </res>
      </rp>
      <rp s="00a595c0-0000-0000-0000-000000000000" ag="1" i="0" j="0" ah="2018-01-29T17:00:00Z" >
        <piData programId="00a595c0-0000-0000-0000-000000000000" al="3"  />
        <res>
          <re o="2018-01-29T17:00:00Z" p="212" q="000000cb-0000-0000-0000-000000000000"  >
            <riData av="false"  az="180"  />
          </re>
        </res>
      </rp>
    </rps>
  </RDData>
</ArrayOfRDData>')

查询:

SELECT 
    [scheduleid],
    StationID_q = ARD3.res.value('@q', 'varchar(max)'),
    ProgramID_s = ARD2.ag.value('@s', 'varchar(max)'),
    StartTime_o = ARD3.res.value('@o', 'datetime') 
FROM
    [DVR_0601].[dbo].testXML Sch 
CROSS APPLY
    Sch.XMLData1.nodes('/ArrayOfRDData/RDData/rps') AS AoD(RDData) 
CROSS APPLY
    AoD.RDData.nodes('rp') AS ARD2(ag) 
CROSS APPLY
    AoD.RDData.nodes('rp/res/re') AS ARD3(res) 
WHERE
    ISNULL( ARD2.ag.value('@ag', 'int'), 0) = 1               

输出:

StationID_q                          ProgramID_s                       StartTime_o

000000cb-0000-0000-0000-000000000000 00a566e2-0000-0000-0000-000000000000   2018-01-10 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a566e2-0000-0000-0000-000000000000    2018-01-26 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a566e2-0000-0000-0000-000000000000    2018-01-31 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a566e2-0000-0000-0000-000000000000    2018-01-29 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a5860a-0000-0000-0000-000000000000    2018-01-10 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a5860a-0000-0000-0000-000000000000    2018-01-26 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a5860a-0000-0000-0000-000000000000    2018-01-31 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a5860a-0000-0000-0000-000000000000    2018-01-29 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a595c0-0000-0000-0000-000000000000    2018-01-10 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a595c0-0000-0000-0000-000000000000    2018-01-26 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a595c0-0000-0000-0000-000000000000    2018-01-31 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a595c0-0000-0000-0000-000000000000    2018-01-29 17:00:00.000

要求输出:

StationID_q ProgramID_s StartTime_o
000000cb-0000-0000-0000-000000000000    00a566e2-0000-0000-0000-000000000000    2018-01-10 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a5860a-0000-0000-0000-000000000000    2018-01-26 17:00:00.000
000000cb-0000-0000-0000-000000000000    00a595c0-0000-0000-0000-000000000000    2018-01-29 17:00:00.000

我在 <rp> 数据行之间进行交叉连接。

另请注意,如果 ag="0" 我想跳过该数据,确实如此,只是它仍然加入该行。我不确定如何加入 <rp><re> 或者是否可能。

您使用交叉应用的次数过多。

SELECT --[scheduleid],
       StationID_q = ARD3.res.value('@q', 'varchar(max)'),
       ProgramID_s = ARD2.ag.value('@s', 'varchar(max)'),
       StartTime_o = ARD3.res.value('@o', 'datetime')
FROM   testXML Sch
---------------- all rp nodes 
CROSS APPLY Sch.XMLData1.nodes('/ArrayOfRDData/RDData/rps/rp') AS ARD2(ag)
---------------- all inner res/re nodes from rp tag 
CROSS APPLY ag.nodes('res/re') AS ARD3(res) 
WHERE       ISNULL(ARD2.ag.value('@ag', 'int'), 0) = 1
StationID_q                          | ProgramID_s                          | StartTime_o        
:----------------------------------- | :----------------------------------- | :------------------
000000cb-0000-0000-0000-000000000000 | 00a566e2-0000-0000-0000-000000000000 | 10/01/2018 17:00:00
000000cb-0000-0000-0000-000000000000 | 00a5860a-0000-0000-0000-000000000000 | 26/01/2018 17:00:00
000000cb-0000-0000-0000-000000000000 | 00a595c0-0000-0000-0000-000000000000 | 29/01/2018 17:00:00

dbfiddle here

这种方法直接从 XML 中读取元数据,只需要一个 CROSS APPLY 而不需要 WHERE(过滤器包含在 nodes()谓词):

SELECT testXML.XMLData1.value('(/ArrayOfRDData/RDData/@q)[1]','uniqueidentifier') AS StationID
      ,a.rps.value('@s','uniqueidentifier') AS ProgramID
      ,a.rps.value('(res/re/@o)[1]','datetime') AS StartTime
FROM testXML
CROSS APPLY testXML.XMLData1.nodes('/ArrayOfRDData/RDData/rps/rp[@ag!=0]') AS a(rps);