sql - 为 SQL Server 中没有子节点的每个 XML 节点创建一列
问题描述
我正在尝试在 SSMS 中查询一个 xml 文件以创建一个表,该表由作为所有 xml 节点列表的第一行和包含其所有值的下一行组成。xml 数据将具有一个重复节点,该节点将为具有该名称的每个重复节点创建一个新行。这是 xml 数据的示例:
<Tests>
<TestAnswers>
<Question1>
<Name>Example</Name>
<Age>23</Age>
<Question1B>
<Title>Singer</Title>
</Questions1B>
</Question1>
<Question2>
<Car></Car>
<Model>Model 1</Model>
<Question2B>
<Year>1986</Year>
<Manufactured></Manufactured>
</Questions2B>
</Question2>
</TestAnswers>
<TestAnswers>
<Question1>
<Name>Santa</Name>
<Age></Age>
<Question1B>
<Title>Writer</Title>
</Questions1B>
</Question1>
<Question2>
<Car>This car</Car>
<Model>Model2</Model>
<Question2B>
<Year></Year>
<Manufactured></Manufactured>
</Questions2B>
</Question2>
</TestAnswers>
</Tests>
我想在 SQL Server 中创建的表应该类似于:
| Name | Age | Title | Car | Model | Year | Manufactured |
-------------------------------------------------------------------------------------------------
1 | Example | 23 | Singer | | Model 1 | 1986 | |
2 | Santa | | Writer | This Car | Model2 | | |
随着 xml 文件随着更多信息而变得更大,将会创建更多行。我不想为包含子节点的 xml 节点创建列。
如何编写查询来执行此任务?
更新
新的 XML 用例,其中将有两列由重复节点组成:
<Tests>
<TestAnswers>
<Question1>
<Name>Example</Name>
<Age>23</Age>
<Other>Other Text</Other>
<Question1B>
<Title>Singer</Title>
<Other></Other>
</Question1B>
</Question1>
<Question2>
<Car></Car>
<Model>Model 1</Model>
<Question2B>
<Year>1986</Year>
<Manufactured></Manufactured>
</Question2B>
</Question2>
</TestAnswers>
<TestAnswers>
<Question1>
<Name>Santa</Name>
<Age></Age>
<Other></Other>
<Question1B>
<Title>Writer</Title>
<Other>Text</Other>
</Question1B>
</Question1>
<Question2>
<Car>This car</Car>
<Model>Model2</Model>
<Question2B>
<Year></Year>
<Manufactured></Manufactured>
</Question2B>
</Question2>
</TestAnswers>
</Tests>
解决方案
此 XML 是否在您的控制之下?
除了它无效(子元素的结束标签<Question2B>
是复数<Questions2B>
)这一事实之外,还有严重的设计缺陷......
最明显的是名称编号,例如<Question1>
和<Question2>
...
如果内容也可能有所不同,请提供更多详细信息。你正在写更多的行,有更多的信息。您的意思是更多相同还是可能还有其他列甚至其他结构?
除此之外,这里还有一些展示原则的一般方法:
DECLARE @xml XML=
N'<Tests>
<TestAnswers>
<Question1>
<Name>Example</Name>
<Age>23</Age>
<Question1B>
<Title>Singer</Title>
</Question1B>
</Question1>
<Question2>
<Car></Car>
<Model>Model 1</Model>
<Question2B>
<Year>1986</Year>
<Manufactured></Manufactured>
</Question2B>
</Question2>
</TestAnswers>
<TestAnswers>
<Question1>
<Name>Santa</Name>
<Age></Age>
<Question1B>
<Title>Writer</Title>
</Question1B>
</Question1>
<Question2>
<Car>This car</Car>
<Model>Model2</Model>
<Question2B>
<Year></Year>
<Manufactured></Manufactured>
</Question2B>
</Question2>
</TestAnswers>
</Tests>';
--这将逐行返回所有答案
SELECT a.query('.')
FROM @xml.nodes('/Tests/TestAnswers') A(a);
--这将逐行返回所有问题
SELECT q.query('.')
FROM @xml.nodes('/Tests/TestAnswers') A(a)
OUTER APPLY a.nodes('*') B(q);
--这将逐行返回所有具有自己文本的节点
SELECT nd.query('.')
FROM @xml.nodes('/Tests/TestAnswers') A(a)
OUTER APPLY a.nodes('*') B(q)
OUTER APPLY q.nodes('//*[text()]') C(nd);
更新
试试这个来获取一个列表,然后使用PIVOT
peraInx
来获取你的表格格式:
WITH Answers AS
(
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS aInx
,a.query('.') AS a
FROM @xml.nodes('/Tests/TestAnswers') A(a)
)
,Questions AS
(
SELECT aInx
,q.query('.') AS q
FROM Answers
OUTER APPLY a.nodes('*') B(q)
)
SELECT aInx
,nd.value('local-name(.)','nvarchar(max)') AS NodeName
,nd.value('text()[1]','nvarchar(max)') AS NodeValue
FROM Questions
OUTER APPLY q.nodes('//*[text()]') C(nd);
推荐阅读
- sqlite - 如何使用 SQLite 创建两个关系表
- mysql - 针对患者表中的 1000 位患者优化此查询
- ios - Xamarin.ios 中的本机 iOS 组件
- java - 我无法使用 twitter4j 库跟踪我自己的推文
- cmd - 拒绝特定用户访问文件夹
- javascript - 未捕获的类型错误:closeBtn.addEventListener 不是 script.js:8 处的函数
- google-bigquery - 将数据集参数添加到列中,以便稍后通过 DataPrep 在 BigQuery 中使用它们
- laravel-5 - 公司签到状态未注册
- laravel - 如何在 Laravel 的 Mail 函数中定义 $to 变量
- c# - xcopy 命令将 app.manifest 从 obj 移动到 bin 文件夹在构建服务器上失败