XML EXPLICIT查询中CDATA指令失效及排序异常问题求助
我来帮你拆解和解决这两个困扰你的SQL问题:
一、CDATA标签插入XML字段后消失的问题
背后的原因
你用FOR XML EXPLICIT生成的带CDATA的XML,一旦存入xml类型的字段,SQL Server就会对这份XML做解析和标准化处理。CDATA本质是XML的语法糖——它的作用是告诉解析器“这段内容里的特殊字符别当成XML标签处理”,但解析完成后,CDATA标签本身就完成使命了,不会被保留在XML的DOM结构里。所以你读取时看不到CDATA标签,但里面的内容是完整的,特殊字符也都被正确处理了。
两种解决方案
如果必须保留CDATA的字面形式:
把results表的GridXML字段类型从xml改成nvarchar(max),这样SQL Server会把它当成纯文本存储,不会解析CDATA标签:ALTER TABLE results ALTER COLUMN GridXML nvarchar(max);之后插入的XML就会完整保留
<![CDATA[...]]>结构。如果只是要确保内容正确(不需要显示CDATA标签):
完全可以继续用xml类型,因为内容已经被正确存储,CDATA的作用已经实现了——特殊字符不会被误解析,只是标签本身被规范化掉了。
二、ORDER BY按字符串排序而非数值排序的问题
为什么会这样
你的GridStart是nvarchar(max)类型,排序时SQL Server会按字符串的字典顺序来排,'10'的第一个字符是'1',ASCII码比'2'小,所以会排在'2'前面,这就是你看到的异常顺序。
快速修复
在排序的时候把GridStart转换成数值类型(比如INT),注意要先过滤掉非数值的GridStart值(比如'GRID'、'END'),避免转换报错。修改你的查询中的ORDER BY子句:
ORDER BY CAST([tr!2!RowId!Element] AS INT)
另外,原查询会因为Table1里有多条对应同一个Grid的记录,导致插入重复的XML到results表,建议加上GROUP BY去重,优化后的完整插入查询如下:
INSERT INTO results SELECT Z.GridName, ( SELECT * FROM ( SELECT 1 [Tag], NULL [Parent], NULL [DocumentElement!1!], NULL [tr!2!], NULL [tr!2!RowId!Element], NULL [tr!2!Col2!CDATA] UNION ALL SELECT 2 AS Tag, 1 AS Parent, 'DocumentElement', GridStart, GridStart, Col2 FROM Table1 S WHERE GridStart != 'GRID' AND GridStart != 'END' AND Z.DataSheetName = S.DataSheetName AND Z.TestCaseName = S.TestCaseName AND Z.GridName = S.GridName AND Z.GridId = S.GridId AND Z.BatchId = S.BatchId ) AS GridData ORDER BY CAST([tr!2!RowId!Element] AS INT) FOR XML EXPLICIT, TYPE ) AS G FROM dbo.Table1 Z GROUP BY Z.GridName, Z.DataSheetName, Z.TestCaseName, Z.GridId, Z.BatchId;
修改后的效果
执行上述修改后:
- 若你选择把
GridXML改成nvarchar(max),CDATA标签会完整出现在结果里; - 排序会按照1、2、3...10的数值顺序排列,不再是字符串顺序。
内容的提问来源于stack exchange,提问作者medic

