无法生成 FOR XML

Unable to generate FOR XML

我受困于 FOR XML。我正在使用 SQL Server 2008。

我正在尝试使用 FOR XML 生成 XML。 请在 http://sqlfiddle.com/#!9/4e180e

查看示例数据

我想将数据转换成以下 XML 格式。我想将标签转换为标签 <Headers> 并将数据转换为数据标签。在我的实际场景中,table 中的列数是动态的。

我会请求您是否可以建议一种动态方式来生成 XML,其中列数不应影响 XML 生成的逻辑。

<RootNode>
    <Subject>
        </SubjectID=94>
        <FORMName>
            <Headers>
                <Header>VISIT</Header>
            </Headers>
            <Datas>
                <Data>1<Data>
            </Datas> 
            <Headers>
                <Header>Date</Header>
            </Headers>
            <Datas>
                <Data>8 Aug<Data>
            </Datas>
            <Headers>
                <Header>Doc Name</Header><Header>Hostipal Name</Header>
            </Headers>
            <Datas>
                <Data>Dr Sam</Data><Data>Happy Memorial</Data>
            </Datas>
            <Datas>
                <Data>Dr Sam</Data><Data>Happy Memorial</Data>
            </Datas>
        </FORMName>
    </Subject>
<RootNode>

我停留在非常初级的水平,无法前进。

请帮助我。

这个结构 - 嗯 - 很奇怪......

您的 table 有点像 Key-Value-Pair,带有 1:n-dependency 的 Header 和数据。这违反了规范化的几条规则...

您的 XML 只能通过 Header 及其数据的相应位置查询。想象一些数据为 NULL,你也必须处理这个......

顺便说一句:您的 </SubjectID=94> 无效...

如果您是这个结构的所有者,您应该考虑一下我该如何改进这个结构?

然而这是可以做到的——虽然我不会:

CREATE TABLE DataCols (
ID INT NOT NULL IDENTITY PRIMARY KEY, 
SubjectID INT, 
FormName VARCHAR(100),
ItemDetail VARCHAR(100),
POSITION INT,
col1 VARCHAR(255),
col2 VARCHAR(255)
);

INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(94,'TOX','Label',0,'Visit');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(94,'TOX','Data',0,'1');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(94,'TOX','Label',0,'Date');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(94,'TOX','Date',0,'8 Aug');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(94,'TOX','Label',1,'Doc Name','Hostipal Name');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(94,'TOX','Data',1,'Dr Sam','Happy Memorial');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(94,'TOX','Data',2,'Dr Sam','Happy Memorial');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(98,'TOX','Label',0,'Visit');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(98,'TOX','Data',0,'1');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(98,'TOX','Label',0,'Date');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1)      VALUES(98,'TOX','Date',0,'4 Jan');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(98,'TOX','Label',1,'Doc Name','Hostipal Name');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(98,'TOX','Data',1,'Dr Sam','Vegas Hostipal');
INSERT INTO DataCols (SubjectID,FormName,ItemDetail,POSITION,col1,col2) VALUES(98,'TOX','Data',2,'Dr Sam','Vegas Hostipal');
GO

--这里是查询:

WITH DistinctID AS
(SELECT DISTINCT SubjectID FROM DataCols)
,Labels AS
(
    SELECT SubjectID
          ,ID
          ,(SELECT col1 AS Header,'',col2 AS Header FOR XML PATH('Headers'),TYPE) AS HeaderXML
    FROM DataCols AS c
    WHERE ItemDetail='Label'
)
,LabelsExt AS
(
    SELECT * 
          ,(SELECT MIN(x.ID) FROM Labels AS x WHERE x.ID>Labels.ID) AS NextID
    FROM Labels
)
SELECT SubjectID
      ,(
        SELECT HeaderXML AS [*]
              ,(SELECT col1 AS Data,'',col2 AS Data 
                FROM DataCols 
                WHERE DataCols.ID BETWEEN l.ID+1 AND ISNULL(l.NextID,999999)-1 FOR XML PATH('Datas'),TYPE)  AS [*]
        FROM LabelsExt AS l
        WHERE l.SubjectID=DistinctID.SubjectID
        FOR XML PATH(''),ROOT('FORMName'),TYPE
       )
FROM DistinctID
FOR XML PATH('Subject'),ROOT('RootNode')

--Clean-Up(真实数据慎重!)

GO
--DROP TABLE DataCols;

更新

您可以尝试将 header 作为属性添加到您的 Data-element 中。一般来说,我更愿意将元素命名为它们本来的样子......只有在动态创建的字段你事先不知道结构的情况下才更喜欢这样的结构。

WITH DistinctID AS
(SELECT DISTINCT SubjectID FROM DataCols)
,Labels AS
(
    SELECT SubjectID
          ,ID
          ,col1,col2
    FROM DataCols AS c
    WHERE ItemDetail='Label'
)
,LabelsExt AS
(
    SELECT * 
          ,(SELECT MIN(x.ID) FROM Labels AS x WHERE x.ID>Labels.ID) AS NextID
    FROM Labels
)
SELECT SubjectID
      ,(
        SELECT (SELECT l.col1 AS [Data/@header], c.col1 AS Data
                      ,''
                      ,l.col2 AS [Data/@header], c.col2 AS Data 
                FROM DataCols AS c 
                WHERE c.ID BETWEEN l.ID+1 AND ISNULL(l.NextID,999999)-1 
                FOR XML PATH('Datas'),TYPE)  AS [*]
        FROM LabelsExt AS l
        WHERE l.SubjectID=DistinctID.SubjectID
        FOR XML PATH(''),ROOT('FORMName'),TYPE
       )
FROM DistinctID
FOR XML PATH('Subject'),ROOT('RootNode')