SQL Server如何将XML内GO分隔符替换为新XML行节点
T-SQL XML批处理节点拆分方案
- 问题根因:直接使用XML
modify方法将GO节点文本置空,仅删除了分隔符文本,没有拆分节点结构,会导致不同批处理的SQL被拼接在同一个节点下,触发 CREATE TRIGGER、CREATE PROCEDURE等DDL语句必须作为批处理首句的执行错误。 - 实现思路:放弃单节点文本替换逻辑,改为按
GO分界位置重组XML节点结构,确保每个节点对应一段可独立执行的完整SQL批处理,适配 sp_execXML存储过程的执行规则:- 将XML内所有
节点按文档顺序展开为扁平序列,标记节点顺序 - 识别所有值为
GO的分界节点,按分界位置给节点划分所属批处理组 - 剔除所有
GO节点,把同组内的SQL文本按原顺序拼接为完整批处理 - 清空原有
节点集合,将每段批处理写入独立的新 节点,按原顺序重组XML
- 将XML内所有
可直接复用的实现代码
-- 变量@TargetXML存储你需要处理的包含触发器脚本的XML内容 DECLARE @TargetXML XML = N' <Root> <Krishna>CREATE TRIGGER trg_OrderInsert ON Orders AFTER INSERT AS BEGIN SET NOCOUNT ON; END</Krishna> <Krishna>GO</Krishna> <Krishna>CREATE TRIGGER trg_OrderUpdate ON Orders AFTER UPDATE AS BEGIN SET NOCOUNT ON; END</Krishna> </Root>' ;WITH NodeSequence AS ( SELECT NodeContent.value('.', 'NVARCHAR(MAX)') AS NodeText, ROW_NUMBER() OVER (ORDER BY NodeContent) AS NodeOrder, -- 每遇到一个GO节点,批处理组号+1 SUM(CASE WHEN LTRIM(RTRIM(UPPER(NodeContent.value('.', 'NVARCHAR(MAX)')))) = 'GO' THEN 1 ELSE 0 END) OVER (ORDER BY NodeContent ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS BatchID FROM @TargetXML.nodes('//Krishna') AS N(NodeContent) ) ,BatchCollection AS ( SELECT BatchID, -- 同组SQL按原顺序拼接,保留换行格式 STRING_AGG(NodeText, CHAR(13) + CHAR(10)) WITHIN GROUP (ORDER BY NodeOrder) AS IndependentBatchSQL FROM NodeSequence -- 过滤掉GO分隔符本身 WHERE LTRIM(RTRIM(UPPER(NodeText))) <> 'GO' GROUP BY BatchID ) -- 重组为符合sp_execXML要求的XML结构 SELECT @TargetXML = ( SELECT IndependentBatchSQL AS [Krishna] FROM BatchCollection ORDER BY BatchID FOR XML PATH(''), ROOT('Root'), TYPE ) -- 处理完成后直接传入存储过程执行即可 -- EXEC sp_execXML @TargetXML
- 兼容说明:代码对
GO做了大小写不敏感匹配、首尾空格裁剪处理,可覆盖go、GO等常见不规范写法;注释内的GO不会被误识别为批处理分隔符,和SSMS、SQLCMD的默认分隔规则一致。 - 验证方法:处理后可直接查询
@TargetXML确认结构,每个节点内的SQL均为独立批处理,不会出现多段DDL拼接的问题。
内容的提问来源于stack exchange,提问作者Marcello Miorelli
相关产品推荐
相关产品推荐

