如何在FOR XML PATH中选择不同的值?

时间:2017-10-31 16:05:42

标签: sql xml sql-server-2008 tsql xpath

鉴于以下表格T_DATA.ID = PARENT_IDCHILD.ID

姓名:T_DATA

+----+------+--------+
| ID | CODE | VALUE  |
+----+------+--------+
|  1 | 3186 | value1 |
|  2 | 3186 | value2 |
|  3 | 3189 | value3 |
|  4 | 3189 | value4 |
|  5 | 3190 | value5 |
+----+------+--------+

姓名:T_DATA_LINK

+-----------+----------+
| PARENT_ID | CHILD_ID |
+-----------+----------+
|         1 |        3 |
|         1 |        4 |
+-----------+----------+

我想返回一个像这样的xml结构:

<ITEM_LIST>
    <ITEM>
        <CODE>3186</CODE>
        <ROWS>
            <ROW>
                <ID>1</ID>
                <ROW_INDEX>0</ROW_INDEX>
                <VALUE>value1</VALUE>
            </ROW>
            <ROW>
                <ID>2</ID>
                <ROW_INDEX>1</ROW_INDEX>
                <VALUE>value2</VALUE>
            </ROW>
        </ROWS>
    </ITEM>
    <ITEM>
        <CODE>3189</CODE>
        <ROWS>
            <ROW>
                <ID>3</ID>
                <ROW_INDEX>0</ROW_INDEX>
                <VALUE>value3</VALUE>
            </ROW>
            <ROW>
                <ID>4</ID>
                <ROW_INDEX>1</ROW_INDEX>
                <VALUE>value4</VALUE>
            </ROW>
        </ROWS>
    </ITEM>
    <ITEM>
        <CODE>3190</CODE>
        <VALUE>value5</VALUE>
    </ITEM>
</ITEM_LIST>

ROW_INDEX ROW加1。

我需要T_DATA_LINK表来了解ITEM是否有父母。

如果它具有父级,则表示存在多个具有CODE值的记录,并且它们需要显示为ROWS,否则必须显示为单个{{1 }}

更新

我实际上需要检查T_DATA_LINK表,因为可能存在ITEM具有父级且只有一条记录的情况,但仍需要将其显示为ROW。

@Shnugo我尝试了你的解决方案,但即使现在我在ROWS中得到正确的值,我也会为每个有多个记录的ITEM获得重复。

这可能是因为我必须将SELECT需要返回的GROUP BY添加到其他字段中,而我没有添加到示例中以保持简单。

例如,对于没有任何行的物品,需要在ITEM级别显示ID。

更新2

@Shnugo你是对的。第3项和第4项是第1项的子项,但您不会在xml中看到这种关系。

所有项目都是独一无二的。

T_DATA_LINK中引用的项目仍然是唯一的,但在我的应用程序中相互链接,它们显示在表格中。 基本上,PARENT是表格的第一列,孩子是其他列。

这是我想要的更新输出。

对于有行的项,ID应始终为-1。

PARENT_CODE应该是父项的CODE(如果项目是父项,那么它等于CODE)

ITEM

1 个答案:

答案 0 :(得分:2)

这是一个新的答案......请尽量将所有需要的信息放入最初的问题......

DECLARE @t_data TABLE(ID INT,CODE INT,VALUE VARCHAR(100));
INSERT INTO @t_data VALUES
 (1,3186,'value1')
,(2,3186,'value2')
,(3,3189,'value3')
,(4,3189,'value4')
,(5,3190,'value5');

DECLARE @t_data_link TABLE(PARENT_ID INT, CHILD_ID INT)
INSERT INTO @t_data_link VALUES
 (1,3)
,(1,4);

- CTE链接两个表并允许将它们作为一个派生的表处理

WITH Combined AS
(
    SELECT d.*
          ,d2.CODE AS PARENT_CODE
          ,COUNT(*) OVER(PARTITION BY d.CODE) AS CountRows 
    FROM @t_data AS d
    LEFT JOIN @t_data_link AS dl ON d.ID=dl.CHILD_ID
    LEFT JOIN @t_data AS d2 ON dl.PARENT_ID=d2.ID
)
SELECT CASE WHEN c.CountRows>1 THEN -1 END AS ID 
      ,CASE WHEN c.CountRows>1 THEN c.CODE END AS CODE
      ,CASE WHEN c.CountRows>1 THEN ISNULL(c.PARENT_CODE,c.CODE) END AS PARENT_CODE
       --This part for elements with just one row per code
      ,(
        SELECT d2.ID
              ,d2.CODE
              ,d2.VALUE
        FROM @t_data AS d2
        WHERE c.CODE=d2.CODE 
          AND c.CountRows=1
        FOR XML PATH(''),TYPE
       )
       --This part for elements with more rows per code
       ,(
        SELECT d2.ID
              ,ROW_NUMBER() OVER(ORDER BY (SELECT NULL))-1 AS ROW_INDEX
              ,d2.VALUE
        FROM @t_data AS d2
        WHERE c.CODE=d2.CODE 
          AND c.CountRows>1
        FOR XML PATH('ROW'),ROOT('ROWS'),TYPE
       )
FROM Combined AS c
GROUP BY c.CODE,c.CountRows,c.PARENT_CODE
FOR XML PATH('ITEM'),ROOT('ITEM_LIST');

结果

<ITEM_LIST>
  <ITEM>
    <ID>-1</ID>
    <CODE>3186</CODE>
    <PARENT_CODE>3186</PARENT_CODE>
    <ROWS>
      <ROW>
        <ID>1</ID>
        <ROW_INDEX>0</ROW_INDEX>
        <VALUE>value1</VALUE>
      </ROW>
      <ROW>
        <ID>2</ID>
        <ROW_INDEX>1</ROW_INDEX>
        <VALUE>value2</VALUE>
      </ROW>
    </ROWS>
  </ITEM>
  <ITEM>
    <ID>-1</ID>
    <CODE>3189</CODE>
    <PARENT_CODE>3186</PARENT_CODE>
    <ROWS>
      <ROW>
        <ID>3</ID>
        <ROW_INDEX>0</ROW_INDEX>
        <VALUE>value3</VALUE>
      </ROW>
      <ROW>
        <ID>4</ID>
        <ROW_INDEX>1</ROW_INDEX>
        <VALUE>value4</VALUE>
      </ROW>
    </ROWS>
  </ITEM>
  <ITEM>
    <ID>5</ID>
    <CODE>3190</CODE>
    <VALUE>value5</VALUE>
  </ITEM>
</ITEM_LIST>

XML将省略任何NULL值。如果找不到任何内容,则子选择中的WHERE子句将返回NULL ...