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

T-SQL循环生成多行XML块仅获最后结果,求解决方法

问题:T-SQL循环生成XML时无法拼接多个块

因应用限制仅能使用T-SQL构建用于Web服务的XML报文,需根据临时表的每行数据生成对应结构的<contentBody>XML块并拼接。

临时表数据

rownumberscrossingnumberequipmentsalesorder
1UK22G1234567ST9999900BJV112345-1
2UK22G8910112ST1234500ABC267891-1

期望生成的XML结果

<contentBody>
  <exportShipment>
    <customsDocument>
      <Type>IN</Type>
      <documentNumber>UK22G1234567</documentNumber>
    </customsDocument>
    <equipment>
      <equipmentNumber>00BJV1</equipmentNumber>
      <reference>ST99999</reference>
    </equipment>
  </exportShipment>
</contentBody>
<contentBody>
  <exportShipment>
    <customsDocument>
      <Type>IN</Type>
      <documentNumber>UK22G8910112</documentNumber>
    </customsDocument>
    <equipment>
      <equipmentNumber>00ABC2</equipmentNumber>
      <reference>ST12345</reference>
    </equipment>
  </exportShipment>
</contentBody>

当前测试代码

DECLARE @Counter INT, @MaxId INT, @number VARCHAR(50), @CrossingNr VARCHAR(50), @Equipment VARCHAR(50), @contentbody XML

DECLARE @tbl TABLE (row INT, numbers VARCHAR(50), crossingnumber VARCHAR(100), equipment VARCHAR(100), salesorder VARCHAR(50))
INSERT INTO @tbl (row, numbers, crossingnumber, equipment, salesorder)  
    VALUES
    (1, 'UK22G1234567', 'ST99999', '00BJV1', '12345-1'),
    (2, 'UK22G8910112', 'ST12345', '00ABC2', '98765-1')

SELECT @Counter = MIN(row) , @MaxId = MAX(row) FROM @tbl
WHILE(@Counter IS NOT NULL AND @Counter <= @MaxId)
    BEGIN
        SELECT @number = numbers FROM @tbl WHERE row = @Counter
        SELECT @CrossingNr = crossingnumber FROM @tbl WHERE row = @Counter
        SELECT @Equipment = equipment FROM @tbl WHERE row = @Counter

        SELECT @contentbody = (
            (SELECT 
                (SELECT 
                    (SELECT 
                        "Type" = 'IN',
                        "documentNumber" = @Number
                    FOR XML PATH('customsDocument'), TYPE),
                    (SELECT 
                        "equipmentNumber" =  @Equipment,
                        "reference" = @CrossingNr
                    FOR XML PATH('equipment'), TYPE)
                FOR XML PATH('exportShipment'), TYPE)
            FOR XML PATH('contentBody'), TYPE)
            )
        SET @Counter  = @Counter  + 1        
    END

SELECT * FROM @tbl
SELECT @contentbody

当前问题:循环遍历逻辑正常,但每次循环会覆盖@contentbody变量,最终仅能得到最后一行的XML结果,无法实现所有XML块的拼接。


解决方案

问题根源

每次循环中直接给@contentbody赋值,会覆盖之前存储的XML内容,而XML变量本身不支持直接追加操作。需要将其转换为字符串类型进行拼接,之后可按需转回XML类型。

修改后的循环代码

DECLARE @Counter INT, @MaxId INT, @number VARCHAR(50), @CrossingNr VARCHAR(50), @Equipment VARCHAR(50), @contentbody NVARCHAR(MAX) = '' -- 改为字符串变量存储

DECLARE @tbl TABLE (row INT, numbers VARCHAR(50), crossingnumber VARCHAR(100), equipment VARCHAR(100), salesorder VARCHAR(50))
INSERT INTO @tbl (row, numbers, crossingnumber, equipment, salesorder)  
    VALUES
    (1, 'UK22G1234567', 'ST99999', '00BJV1', '12345-1'),
    (2, 'UK22G8910112', 'ST12345', '00ABC2', '98765-1')

SELECT @Counter = MIN(row) , @MaxId = MAX(row) FROM @tbl
WHILE(@Counter IS NOT NULL AND @Counter <= @MaxId)
    BEGIN
        SELECT @number = numbers FROM @tbl WHERE row = @Counter
        SELECT @CrossingNr = crossingnumber FROM @tbl WHERE row = @Counter
        SELECT @Equipment = equipment FROM @tbl WHERE row = @Counter

        -- 生成当前行的XML并转换为字符串,追加到@contentbody
        SET @contentbody = @contentbody + CAST((
            (SELECT 
                (SELECT 
                    (SELECT 
                        "Type" = 'IN',
                        "documentNumber" = @Number
                    FOR XML PATH('customsDocument'), TYPE),
                    (SELECT 
                        "equipmentNumber" =  @Equipment,
                        "reference" = @CrossingNr
                    FOR XML PATH('equipment'), TYPE)
                FOR XML PATH('exportShipment'), TYPE)
            FOR XML PATH('contentBody'), TYPE) AS NVARCHAR(MAX))
        
        SET @Counter  = @Counter  + 1        
    END

-- 输出最终拼接结果,可选择字符串或XML类型
SELECT @contentbody AS FinalXMLString
-- SELECT CAST(@contentbody AS XML) AS FinalXML

更优方案:避免循环,直接用集合式XML生成

T-SQL的FOR XML支持直接基于表数据批量生成目标XML,无需循环,效率更高:

DECLARE @tbl TABLE (row INT, numbers VARCHAR(50), crossingnumber VARCHAR(100), equipment VARCHAR(100), salesorder VARCHAR(50))
INSERT INTO @tbl (row, numbers, crossingnumber, equipment, salesorder)  
    VALUES
    (1, 'UK22G1234567', 'ST99999', '00BJV1', '12345-1'),
    (2, 'UK22G8910112', 'ST12345', '00ABC2', '98765-1')

SELECT 
    (SELECT 
        (SELECT 
            'IN' AS "Type",
            t.numbers AS "documentNumber"
        FOR XML PATH('customsDocument'), TYPE),
        (SELECT 
            t.equipment AS "equipmentNumber",
            t.crossingnumber AS "reference"
        FOR XML PATH('equipment'), TYPE)
    FOR XML PATH('exportShipment'), TYPE)
FROM @tbl t
FOR XML PATH('contentBody'), TYPE, ROOT('') -- ROOT('')去掉默认根节点

该方案直接通过表数据生成所有<contentBody>块,结果与期望完全一致,且性能优于循环写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 14:35:45