SQL Server 2014导出XML为单行无格式,代码是否正确?
SQL Server导出XML无格式展示及代码优化建议
问题描述
我使用SQL Server 2014,刚接触XML技术。现尝试将3张关联表导出为XML,表结构为Property(父表)、PropertyArea(子表)、PropertyNotes(子表),通过主键[property_id]与外键实现Property对两个子表的左关联。我编写了如下SQL代码:
DECLARE @XMLOutput XML DECLARE @XMLOutputChar nvarchar(max) ;WITH XMLNAMESPACES('MyNameSpace' as ns) SELECT @XMLOutput = ( SELECT ISNULL(T1.[propertyusercode],'')AS propertyusercode, ISNULL(T1.[NAME],'')AS [NAME], ( SELECT ( SELECT [AreaCode] ,[AreaDesc] FROM [PropertyArea] WHERE [Property_Id] = T1.property_id FOR XML PATH('Area'), TYPE ) FOR XML PATH('Area'), TYPE ), ( SELECT ( SELECT [NotesModuleNumber] ,[NotesPageNumber] ,[NotesText] FROM [PropertyNotes] WHERE [Property_Id] = T1.property_id FOR XML PATH('Notes'), TYPE ) FOR XML PATH('Notes'), TYPE ) FROM Property T1 FOR XML PATH('Property'),TYPE, ROOT('Loader'),ELEMENTS XSINIL ) SET @XMLOutputChar = '<?xml version="1.0" encoding="UTF-8"?>' + CONVERT(nvarchar(max),@XMLOutput) SELECT @XMLOutputChar AS XMLOutput但导出的XML在Notepad++中显示为单行无格式,与预期的格式化展示不符,请问我是否遗漏了什么?代码是否正确?
解答
一、XML无格式展示的原因及解决办法
SQL Server默认生成的XML是紧凑的单行格式,不会自动添加缩进、换行等格式化标记——这是为了减少数据体积,更适合存储和传输。要在Notepad++里看到格式化后的XML很简单:
- 确保你安装了
XML Tools插件(没装的话,通过Plugins > Plugins Admin搜索安装即可) - 打开XML文件后,使用快捷键
Ctrl+Alt+Shift+B,或者通过菜单Plugins > XML Tools > Pretty print (XML only - with line breaks)就能一键格式化。
如果想让SQL Server直接输出带格式的XML,其实SQL Server本身没有内置函数支持,而且带格式的XML会增加额外体积,不推荐这么做,更建议在客户端工具(比如SSMS的XML查看器、Notepad++)里处理格式。
二、代码的正确性检查与优化
你的代码整体逻辑是对的,但存在几个可以优化的地方,同时有一个小问题需要修正:
- 冗余的子查询嵌套
你在子表查询里嵌套了两层FOR XML PATH,比如PropertyArea的部分:
( SELECT ( SELECT [AreaCode] ,[AreaDesc] FROM [PropertyArea] WHERE [Property_Id] = T1.property_id FOR XML PATH('Area'), TYPE ) FOR XML PATH('Area'), TYPE )
这种写法会生成多余的节点层级,比如:
<Area> <Area> <AreaCode>...</AreaCode> <AreaDesc>...</AreaDesc> </Area> </Area>
这显然不是你想要的父子表结构,应该简化为单层子查询。如果希望子表记录放在一个统一的容器节点里(比如<Areas>),可以改成:
(SELECT [AreaCode], [AreaDesc] FROM [PropertyArea] WHERE [Property_Id] = T1.property_id FOR XML PATH('Area'), ROOT('Areas'), TYPE)
这样生成的结构更清晰:
<Areas> <Area> <AreaCode>...</AreaCode> <AreaDesc>...</AreaDesc> </Area> <Area> <AreaCode>...</AreaCode> <AreaDesc>...</AreaDesc> </Area> </Areas>
- XML声明的潜在问题
你手动拼接了XML声明<?xml version="1.0" encoding="UTF-8"?>,但SQL Server的XML类型内部是UTF-16编码的,转成nvarchar(max)后手动添加UTF-8声明可能会导致编码不一致。如果需要正确的XML声明,更推荐:
- 使用SSMS的“结果另存为”功能,选择XML格式,它会自动添加正确的声明和格式
- 用
bcp命令导出XML,能保证编码和声明的一致性
- 左关联的实现是正确的
你通过子查询的WHERE [Property_Id] = T1.property_id结合ELEMENTS XSINIL,能正确实现左关联——即使子表没有对应记录,也会生成空节点,符合需求。
修正后的完整代码
DECLARE @XMLOutput XML ;WITH XMLNAMESPACES('MyNameSpace' as ns) SELECT @XMLOutput = ( SELECT ISNULL(T1.[propertyusercode],'') AS propertyusercode, ISNULL(T1.[NAME],'') AS [NAME], -- 优化后的PropertyArea查询,生成带容器节点的子表结构 (SELECT [AreaCode], [AreaDesc] FROM [PropertyArea] WHERE [Property_Id] = T1.property_id FOR XML PATH('Area'), ROOT('Areas'), TYPE), -- 优化后的PropertyNotes查询 (SELECT [NotesModuleNumber], [NotesPageNumber], [NotesText] FROM [PropertyNotes] WHERE [Property_Id] = T1.property_id FOR XML PATH('Notes'), ROOT('NotesList'), TYPE) FROM Property T1 FOR XML PATH('Property'), TYPE, ROOT('Loader'), ELEMENTS XSINIL ) -- 直接返回XML类型,在SSMS中点击结果可查看格式化后的XML SELECT @XMLOutput AS XMLOutput
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

