FOR XML EXPLICIT - 重复属性值

FOR XML EXPLICIT - repeats attributes values

我需要生成一个 EXCEL Like XML 文件,从 table 服务器中的 table 插入数据。经过一些研究,我有以下 SQL 使用 FOR XML EXPLICIT 模式的服务器脚本:

DECLARE @T AS TABLE (col1 VARCHAR(20), col2 VARCHAR(20));
INSERT INTO @T VALUES('Row1 Col1', 'Row1 Col2');
INSERT INTO @T VALUES('Row2 Col1', 'Row2 Col2');

SELECT 1   as 'Tag'
  ,NULL  as 'Parent'
  ,NULL  as 'Row!1'
  ,NULL  as 'Cell!2'
  ,NULL  as 'Cell!2!Index'
  ,NULL  as 'Cell!2!StyleID'
  ,NULL  as 'Data!3'
  ,NULL  as 'Data!3!Type'
  ,NULL  as 'Cell!2'
  ,NULL  as 'Cell!2!Index'
  ,NULL  as 'Cell!2!StyleID'
  ,NULL  as 'Data!3'
  ,NULL  as 'Data!3!Type'
  ,ROW_NUMBER() OVER (ORDER BY col1) as 'Row!1!A!HIDE'
  ,1   as 'Row!1!B!HIDE'
FROM @T
UNION ALL
SELECT 2
  ,1
  ,NULL
  ,NULL
  ,'1'
  ,'s1'
  ,NULL
  ,NULL
  ,NULL
  ,'2'
  ,'s2'
  ,NULL
  ,NULL
  ,ROW_NUMBER() OVER (ORDER BY col1)
  ,2
FROM @T
UNION ALL
SELECT 3
  ,2
  ,NULL
  ,NULL
  ,NULL
  ,NULL
  ,col1
  ,'String'
  ,NULL
  ,NULL
  ,NULL
  ,col2
  ,'String'
  ,ROW_NUMBER() OVER (ORDER BY col1)
  ,3
FROM @T
ORDER BY 14, 15
FOR XML EXPLICIT

GO

我得到的结果是:

<Row>
  <Cell Index="1" StyleID="s1" Index="2" StyleID="s2">
    <Data Type="String" Type="String">Row1 Col1Row1 Col2</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1" Index="2" StyleID="s2">
    <Data Type="String" Type="String">Row2 Col1Row2 Col2</Data>
  </Cell>
</Row>

我期望的结果是:

<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row1 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row1 Col2</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row2 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row2 Col2</Data>
  </Cell>
</Row>

如有任何帮助,我们将不胜感激。

这应该能得到您想要的结果,但不确定这是否仅适用于您提供的测试数据。

SELECT
    1 AS 'Tag',
    NULL AS 'Parent',
    NULL AS 'Row!1',
    NULL AS 'Cell!2',
    NULL AS 'Cell!2!Index',
    NULL AS 'Cell!2!StyleID',
    NULL AS 'Data!3',
    NULL AS 'Data!3!Type',
    ROW_NUMBER() OVER (ORDER BY col1) AS 'Row!1!A!HIDE',
    1 AS 'Row!1!B!HIDE'
FROM
    @T
UNION ALL
SELECT
    2,
    1,
    NULL,
    NULL,
    '1',
    's1',
    NULL,
    NULL,
    ROW_NUMBER() OVER (ORDER BY col1),
    2
FROM
    @T
UNION ALL
SELECT
    3,
    2,
    NULL,
    NULL,
    NULL,
    NULL,
    col1,
    'String',
    ROW_NUMBER() OVER (ORDER BY col1),
    2
FROM
    @T
UNION ALL
SELECT
    2,
    1,
    NULL,
    NULL,
    '2',
    's2',
    NULL,
    NULL,
    ROW_NUMBER() OVER (ORDER BY col1),
    3
FROM
    @T
UNION ALL    
SELECT
    3,
    2,
    NULL,
    NULL,
    NULL,
    NULL,
    col2,
    'String',
    ROW_NUMBER() OVER (ORDER BY col1),
    3
FROM
    @T
ORDER BY
    9,
    10
FOR   
    XML EXPLICIT 

GO

诀窍是在调用之前以正确的顺序获取数据 FOR XML EXPLICIT 它应该类似于此

Tag Parent  Row!1  Cell!2  Cell!2!Index  Cell!2!StyleID  Data!3     Data!3!Type  Row!1!A!HIDE  Row!1!B!HIDE
1   NULL    NULL   NULL    NULL          NULL            NULL       NULL         1             1
2   1       NULL   NULL    1             s1              NULL       NULL         1             2
3   2       NULL   NULL    NULL          NULL            Row1 Col1  String       1             2
2   1       NULL   NULL    2             s2              NULL       NULL         1             3
3   2       NULL   NULL    NULL          NULL            Row1 Col2  String       1             3
1   NULL    NULL   NULL    NULL          NULL            NULL       NULL         2             1
2   1       NULL   NULL    1             s1              NULL       NULL         2             2
3   2       NULL   NULL    NULL          NULL            Row2 Col1  String       2             2
2   1       NULL   NULL    2             s2              NULL       NULL         2             3
3   2       NULL   NULL    NULL          NULL            Row2 Col2  String       2             3

我设法使用 FOR XML PATH 模式找到了一个更好的方法:

DECLARE @T AS TABLE (
  col1 VARCHAR(20),
  col2 VARCHAR(20),
  col3 VARCHAR(20)
);

INSERT INTO @T VALUES
  ('Row1 Col1','Row1 Col2','Row1 Col3'),
  ('Row2 Col1',NULL,'Row2 Col3'),
  ('Row3 Col1','Row3 Col2',NULL);

SELECT
  '1'      as 'Cell/@Index',
  's1'     as 'Cell/@StyleID',
  'String' as 'Cell/Data/@Type',
  col1     as 'Cell/Data',
  '',
  '2'      as 'Cell/@Index',
  's2'     as 'Cell/@StyleID',
  'String' as 'Cell/Data/@Type',
  col2     as 'Cell/Data',
  '',
  '3'      as 'Cell/@Index',
  's3'     as 'Cell/@StyleID',
  'String' as 'Cell/Data/@Type',
  col3     as 'Cell/Data'
FROM @T
FOR XML PATH ('Row')

GO

我得到了想要的结果:

<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row1 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row1 Col2</Data>
  </Cell>
  <Cell Index="3" StyleID="s3">
    <Data Type="String">Row1 Col3</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row2 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String" />
  </Cell>
  <Cell Index="3" StyleID="s3">
    <Data Type="String">Row2 Col3</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row3 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row3 Col2</Data>
  </Cell>
  <Cell Index="3" StyleID="s3">
    <Data Type="String" />
  </Cell>
</Row>

在 sql 语句中添加空字符串 (´´) 就可以了。

但情况正在好转:我不想为 NULL 值打印标签。我应该如何管理这个?这是答案:

DECLARE @T AS TABLE (
  col1 VARCHAR(20),
  col2 VARCHAR(20),
  col3 VARCHAR(20)
);

INSERT INTO @T VALUES
  ('Row1 Col1','Row1 Col2','Row1 Col3'),
  ('Row2 Col1',NULL,'Row2 Col3'),
  ('Row3 Col1','Row3 Col2',NULL);

SELECT
  'Cell/@Index'     = case when col1 is not null then '1'      else NULL end,
  'Cell/@StyleID'   = case when col1 is not null then 's1'     else NULL end,
  'Cell/Data/@Type' = case when col1 is not null then 'String' else NULL end,
  col1              as 'Cell/Data',
  '',
  'Cell/@Index'     = case when col2 is not null then '2'      else NULL end,
  'Cell/@StyleID'   = case when col2 is not null then 's2'     else NULL end,
  'Cell/Data/@Type' = case when col2 is not null then 'String' else NULL end,
  col2              as 'Cell/Data',
  '',
  'Cell/@Index'     = case when col3 is not null then '3'      else NULL end,
  'Cell/@StyleID'   = case when col3 is not null then 's3'     else NULL end,
  'Cell/Data/@Type' = case when col3 is not null then 'String' else NULL end,
  col3              as 'Cell/Data'
FROM @T
FOR XML PATH ('Row')

GO

我得到了更好的结果:

<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row1 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row1 Col2</Data>
  </Cell>
  <Cell Index="3" StyleID="s3">
    <Data Type="String">Row1 Col3</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row2 Col1</Data>
  </Cell>
  <Cell Index="3" StyleID="s3">
    <Data Type="String">Row2 Col3</Data>
  </Cell>
</Row>
<Row>
  <Cell Index="1" StyleID="s1">
    <Data Type="String">Row3 Col1</Data>
  </Cell>
  <Cell Index="2" StyleID="s2">
    <Data Type="String">Row3 Col2</Data>
  </Cell>
</Row>

我是在 SQLS 2008 上使用 CASE 完成的。对于 SQLS 2012,您可以改用 IIF。

最后,我想在属性上添加一个名称空间指示器。我这样做了:

DECLARE @T AS TABLE (
  col1 VARCHAR(20),
  col2 VARCHAR(20),
  col3 VARCHAR(20)
);

INSERT INTO @T VALUES
  ('Row1 Col1','Row1 Col2','Row1 Col3'),
  ('Row2 Col1',NULL,'Row2 Col3'),
  ('Row3 Col1','Row3 Col2',NULL);

WITH XMLNAMESPACES ('urn:schemas-microsoft-com:office:spreadsheet' as ss)
SELECT
  'Cell/@ss:Index'     = case when col1 is not null then '1'      else NULL end,
  'Cell/@ss:StyleID'   = case when col1 is not null then 's1'     else NULL end,
  'Cell/Data/@ss:Type' = case when col1 is not null then 'String' else NULL end,
  col1              as 'Cell/Data',
  '',
  'Cell/@ss:Index'     = case when col2 is not null then '2'      else NULL end,
  'Cell/@ss:StyleID'   = case when col2 is not null then 's2'     else NULL end,
  'Cell/Data/@ss:Type' = case when col2 is not null then 'String' else NULL end,
  col2              as 'Cell/Data',
  '',
  'Cell/@ss:Index'     = case when col3 is not null then '3'      else NULL end,
  'Cell/@ss:StyleID'   = case when col3 is not null then 's3'     else NULL end,
  'Cell/Data/@ss:Type' = case when col3 is not null then 'String' else NULL end,
  col3              as 'Cell/Data'
FROM @T
FOR XML PATH ('Row'), ROOT ('Worksheet')

GO

我得到了一个与我正在寻找的结果更接近的结果:

<Worksheet xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
  <Row>
    <Cell ss:Index="1" ss:StyleID="s1">
      <Data ss:Type="String">Row1 Col1</Data>
    </Cell>
    <Cell ss:Index="2" ss:StyleID="s2">
      <Data ss:Type="String">Row1 Col2</Data>
    </Cell>
    <Cell ss:Index="3" ss:StyleID="s3">
      <Data ss:Type="String">Row1 Col3</Data>
    </Cell>
  </Row>
  <Row>
    <Cell ss:Index="1" ss:StyleID="s1">
      <Data ss:Type="String">Row2 Col1</Data>
    </Cell>
    <Cell ss:Index="3" ss:StyleID="s3">
      <Data ss:Type="String">Row2 Col3</Data>
    </Cell>
  </Row>
  <Row>
    <Cell ss:Index="1" ss:StyleID="s1">
      <Data ss:Type="String">Row3 Col1</Data>
    </Cell>
    <Cell ss:Index="2" ss:StyleID="s2">
      <Data ss:Type="String">Row3 Col2</Data>
    </Cell>
  </Row>
</Worksheet>

我必须将这个片段插入 XML 文档的中间,所以如果我能去掉第一行和最后一行以连接固定的页眉和页脚,那就太好了。

希望这对其他人有帮助。