关于“FOR XML EXPLICIT”故障排除的建议消息6833“需要先打开父标记”错误

时间:2010-12-17 00:01:06

标签: sql-server xml

我继承了一个1000行的存储过程,它使用FOR XML EXPLICIT生成XML。我的问题是它大部分时间都有效。在某些情况下,我收到错误:

  

父标记ID 2不在打开状态   标签。 FOR XML EXPLICIT需要父级   要先打开的标签。检查   排序结果集。   号码:6833严重性:16状态:1

我需要有关如何排除故障的想法。我需要找出嵌套失败的地方。这可能是父行没有被发射而是子行的情况。更糟糕的是,问题只发生在我们的测试系统上,这可能会遗漏一些生产数据。问题是如何从成千上万行中找到它?

我确定不存在一个疯狂的想法:SQL Server有一个算法,用于确定行是否按正确顺序排列。如果有一个工具可以查看我的结果集(没有FOR XML EXPLICIT)并找出问题所在,那就太棒了(如果不太可能),那就告诉我它。

如果没有这样的工具,我欢迎任何关于如何调试它的建议。 XML(当它工作时)深入四层!


更新:感谢目前为止的所有答案。看起来这是一个编辑严重的存储过程的问题。大部分用“/ * /”注释注释掉 - 当代码中已经有“/ * /”注释时这些注释不能很好...当我发布时我会再次更新确定答案。

4 个答案:

答案 0 :(得分:8)

一种可能的方法是实际删除FOR XML EXPLICIT部分并查看sql语句生成的结果集。它将指示生成xml的嵌套,并希望引导您解决问题。请参阅以下图片,该图片取自MSDN文档: http://msdn.microsoft.com/en-us/library/ms189068.aspx

alt text


修改

可能值得发布示例输出,但是在图像的示例中,如果Order!2的任何行的订单为2!Id,则会得到相同的错误。此列实际上是tag = 2的父行和tag = 3的子行之间的连接。如果您的数据如上所述,我认为您可以通过识别parent = 2和Order!2的行来有效地找到您的问题!Id为空。

或者可以订购。在这种情况下,您可以以某种方式构建一个查询,以识别在结果集中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

答案 1 :(得分:3)

使用FOR XML时,结果集的顺序必须在其子项之前具有父xml节点(通常,XML文件不应该依赖于被排序;这应该使用XSL转换来执行)

感兴趣:The Art of XSD(免费电子书)

您可能已经知道了这一点:如果您有XSD,您可以使用工具根据XSD验证XML(或者编写大约10行C#来执行此操作):

How To Validate an XML Document by Using DTD, XDR, or XSD in Visual C# .NET

如果您有格式良好的XML示例,则可以使用XSD.exe生成XSD。

答案 2 :(得分:2)

我将rowset(没有FOR XML子句)转储到临时表中。然后,您应该能够在此表中为孤儿执行搜索。

如果您找不到任何孤儿,则表示您的订购存在问题(父级位于行集中,但显示在子级之后)。但至少我们会将问题的搜索空间减半: - )

答案 3 :(得分:2)

我找到了其中一个问题的答案,并希望分享我学到的一些经验教训。

我获取了存储过程的内容,并对其进行了更改,以便将结果集插入到表变量中。第1课:确保在表变量中获得正确的列类型 - 我花了数小时追逐由于无意中将列类型从varchar更改为int而导致的问题,这导致排序顺序的更改,从而解决了问题。

一旦修复了我的表变量,我就可以做一些有用的查询,比如:

SELECT TOP n *
FROM @result
ORDER BY <same order as original query>
FOR XML EXPLICIT

我以为我必须做一个“二分搜索”来确定哪一行有问题。事实证明,问题出在前几行。

2级数据由查询形成,该查询包括查找表的内部联接。只要查找列没有映射,就会导致整行被省略。这并没有阻止发出相应的3级和4级行,因此导致错误。

使用LEFT JOIN进行查找解决了问题。