无法生成FOR XML

时间:2016-08-10 20:02:43

标签: xml sql-server-2008 for-xml-path for-xml

我被FOR XML困住了。我正在使用SQL Server 2008。

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

上的示例数据

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

我会请求你是否可以建议一种生成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>

我陷入了初始阶段,无法前进。

请帮帮我。

1 个答案:

答案 0 :(得分:1)

这种结构是 - 嗯 - 很奇怪......

您的表格类似于Key-Value-Pair,其中包含1:n-dependency标题和数据。这违反了几个规范化规则......

您的XML只能通过标题及其数据的相应位置进行查询。试想一些数据为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')

- 清理(如果有真实数据,请小心!)

GO
--DROP TABLE DataCols;

更新

您可以尝试将此标题作为属性添加到数据元素中。一般来说,我更喜欢将元素命名为它们是什么......这样的结构只是在动态创建的字段的情况下,而不是事先知道结构。

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')