提问人:John Saunders 提问时间:12/17/2010 最后编辑:downwitchJohn Saunders 更新时间:2/4/2020 访问量:7642
有关解决“FOR XML EXPLICIT”消息 6833“需要首先打开父标记”错误的建议
Suggestions on Troubleshooting "FOR XML EXPLICIT" Msg 6833 "requires parent tags to be opened first" Error
问:
我继承了一个 1000 行的存储过程,它使用 FOR XML EXPLICIT 生成 XML。我的问题是它大部分时间都有效。在某些情况下,我收到错误:
父标记 ID 2 不在打开标记中 标签。FOR XML EXPLICIT 需要父级 标记。检查 结果集的排序。 编号:6833 严重性:16 状态:1
我需要有关如何解决此问题的想法。我需要找出嵌套失败的地方。这可能是父行未发出但子行发出的情况。更糟糕的是,问题只发生在我们的测试系统上,它可能缺少一些生产数据。问题是如何从数千行中找到它?
一个我确信不存在的疯狂想法:SQL Server 有一种算法用于确定行的顺序是否正确。如果有一个工具可以查看我的结果集(没有 FOR XML EXPLICIT)并找出问题所在,然后告诉我它,那就太好了(如果不太可能的话)。
在没有这样的工具的情况下,我欢迎任何关于如何调试它的建议。XML(当它工作时)有四个层次!
更新:感谢到目前为止的所有答案。看起来这是一个编辑不当的存储过程的问题。大部分部分都用“/* /”注释注释掉了 - 当代码中已经有“/*/”注释时,这些注释效果不佳......当我确定答案时,我会再次更新。
答:
使用 FOR XML 时,结果集的顺序必须将父 xml 节点置于其子节点之前(通常,XML 文件不应依赖于排序;这应使用 XSL 转换来执行)
感兴趣的: XSD 的艺术(免费电子书)
您可能已经知道这一点:如果您有 XSD,则可以使用工具根据 XSD 验证 XML(或编写大约 10 行 C# 来执行此操作):
如何在 Visual C#.net 中使用 DTD、XDR 或 XSD 验证 XML 文档
如果您有格式正确的 XML 示例,则可以使用 生成 XSD。XSD.exe
评论
一种可能的方法是实际删除 FOR XML EXPLICIT 部分,并查看由 sql 语句生成的结果集。它将指示生成 xml 的嵌套,并希望将您引导到该问题。请参阅下图,该图像摘自 MSDN 文档,网址为:http://msdn.microsoft.com/en-us/library/ms189068.aspx。
编辑
可能值得发布示例输出,但在图像中的示例中,如果 Order!2!tag=3 的任何行的 ID 均为 null。此列实际上是 tag=2 的父行和 tag=3 的子行之间的联接。如果您的数据如上所述,我认为您可以通过识别具有 parent=2 和 Order!2 的行来有效地找到您的问题!Id 为 null。
或者,它可以是订购的。在这种情况下,您可以以某种方式生成一个查询,该查询标识结果集中 Tag = 2 的行之前出现的任何 Parent = 2 行。
编辑 2
CREATE TABLE MyTable(
Tag int,
Parent int,
SomeIdentifier int
)
INSERT INTO MyTable VALUES (2, 1, 1) -- this row defined before parent
INSERT INTO MyTable VALUES (1, null, 1)
INSERT INTO MyTable VALUES (3, 2, 1)
INSERT INTO MyTable VALUES (3, 2, 1)
INSERT INTO MyTable VALUES (1, null, 2)
INSERT INTO MyTable VALUES (2, 1, 2)
INSERT INTO MyTable VALUES (3, 2, 2)
INSERT INTO MyTable VALUES (3, 2, 2)
INSERT INTO MyTable VALUES (1, null, 3)
INSERT INTO MyTable VALUES (3, 2, 3) -- this is orphaned
INSERT INTO MyTable VALUES (3, 2, 3) -- this is orphaned
;WITH myCte AS(
SELECT Tag
,Parent
,SomeIdentifier
,ROW_NUMBER() OVER (PARTITION BY SomeIdentifier ORDER BY(SELECT 0)) AS RowOrder
FROM MyTable
) SELECT c1.Tag
,c1.Parent
,c1.SomeIdentifier
FROM myCte c1
LEFT OUTER JOIN myCte c2 ON c2.SomeIdentifier = c1.SomeIdentifier AND c1.Parent = c2.Tag
WHERE c1.Parent IS NOT NULL --ignore root rows for now
AND (c1.RowOrder < c2.RowOrder --out of order rows
OR
c2.Tag IS NULL) --orphaned rows
评论
我会将行集(不带 FOR XML 子句)转储到临时表中。然后,您应该能够在此表中搜索孤立项。
如果找不到任何孤立项,则往往表明您的排序存在问题(父项位于行集中,但显示在子项之后)。但至少我们会将该问题的搜索空间减半:-)
我找到了其中一个问题的答案,并想分享一些我学到的经验教训。
我利用了存储过程的胆量,并对其进行了更改,以便它将结果集插入到表变量中。第 1 课:确保表变量中的列类型正确无误 - 我花了几个小时来追踪一个由于无意中将列类型从 varchar 更改为 int 而引起的问题,这导致了排序顺序的更改,从而移动了问题。
一旦我修复了我的表变量,我就能够做一些有用的查询,比如:
SELECT TOP n *
FROM @result
ORDER BY <same order as original query>
FOR XML EXPLICIT
我以为我必须做一个“二进制搜索”来确定哪一行有问题。事实证明,问题出在前几行。
第 2 级数据由查询组成,该查询包括与查找表的内部联接。这会导致每当查找列未映射时,都会省略整行。这并没有阻止发出相应的 3 级和 4 级行,因此这导致了错误。
使用 LEFT JOIN 进行查找解决了该问题。
评论