You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cross apply返回过多行问题咨询(含testXML表DDL与插入语句)

解决CROSS APPLY返回过多行的问题

我来帮你搞定这个CROSS APPLY返回行数超预期的问题!首先咱们先把你的表结构和插入数据贴出来,方便对照分析:

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" />
<!-- 这里应该还有更多rp节点或者其他内容 -->
</rps>
</RDData>
</ArrayOfRDData>')

常见原因分析

CROSS APPLY返回过多行,大多和XML节点的嵌套结构以及你的查询逻辑有关:

  • 嵌套节点展开导致的正常多行:如果你的XML里一个<RDData>下有多个<rp>节点,用CROSS APPLY逐层展开时,会把每个<rp>都拆成单独一行,这其实是正常的解析结果,但如果你误以为只会返回一行,就会觉得行数过多。
  • 错误的节点关联导致笛卡尔积:如果你的查询里多次CROSS APPLY根节点下的同一层级(比如同时展开两次/ArrayOfRDData/RDData),就会产生笛卡尔积,行数直接爆炸成n²。
  • 未注意到XML里有多个同级节点:比如你的XML里可能不止一个<RDData>,而你没意识到,展开后自然行数变多。

针对性解决方案

1. 先确认XML节点数量

先搞清楚你的XML里到底有多少个目标节点,比如查一下有多少个<RDData>:

SELECT 
    t.scheduleid,
    COUNT(*) AS RDData_总数
FROM testXML t
CROSS APPLY t.XMLData1.nodes('/ArrayOfRDData/RDData') AS RD(rd)
GROUP BY t.scheduleid

再查每个<RDData>下有多少个<rp>:

SELECT 
    t.scheduleid,
    rd.value('@h', 'NVARCHAR(100)') AS RD_Title,
    COUNT(*) AS RP_数量
FROM testXML t
CROSS APPLY t.XMLData1.nodes('/ArrayOfRDData/RDData') AS RD(rd)
CROSS APPLY rd.nodes('rps/rp') AS RP(rp)
GROUP BY t.scheduleid, rd.value('@h', 'NVARCHAR(100)')

2. 修正CROSS APPLY的层级关联

如果是因为错误关联导致笛卡尔积,要确保下一层的CROSS APPLY是基于上一层的节点,而不是重新从根节点开始:

-- 正确的逐层展开写法:每个rp都属于对应的RDData
SELECT 
    t.scheduleid,
    rd.value('@h', 'NVARCHAR(100)') AS Title,
    rd.value('@o', 'DATETIME') AS 时间,
    rp.value('@s', 'UNIQUEIDENTIFIER') AS RP_ID,
    rp.value('@ag', 'INT') AS RP_AG
FROM testXML t
CROSS APPLY t.XMLData1.nodes('/ArrayOfRDData/RDData') AS RD(rd)
-- 这里用rd.nodes,而不是t.XMLData1.nodes,确保关联到父节点
CROSS APPLY rd.nodes('rps/rp') AS RP(rp)

3. 按需过滤或限制行数

如果你不需要所有子节点,只想取每个<RDData>下的第一个<rp>,可以用节点索引:

SELECT 
    t.scheduleid,
    rd.value('@h', 'NVARCHAR(100)') AS Title,
    rp.value('@s', 'UNIQUEIDENTIFIER') AS 第一个RP_ID
FROM testXML t
CROSS APPLY t.XMLData1.nodes('/ArrayOfRDData/RDData') AS RD(rd)
-- 只取第一个rp节点
CROSS APPLY rd.nodes('rps/rp[1]') AS RP(rp)

如果有些<RDData>没有<rp>节点,你想保留这些行,就把CROSS APPLY换成OUTER APPLY。

4. 聚合子节点数据

如果需要把同一<RDData>下的所有<rp>数据聚合起来(比如拼接成字符串),可以用FOR XML PATH:

SELECT 
    t.scheduleid,
    rd.value('@h', 'NVARCHAR(100)') AS Title,
    STUFF(
        (SELECT ',' + rp.value('@s', 'NVARCHAR(50)')
         FROM rd.nodes('rps/rp') AS RP(rp)
         FOR XML PATH('')),
        1, 1, ''
    ) AS 所有RP_ID
FROM testXML t
CROSS APPLY t.XMLData1.nodes('/ArrayOfRDData/RDData') AS RD(rd)

内容的提问来源于stack exchange,提问作者Ron Gordon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:14:55