如何使用日期过滤器查询XML字段

时间:2016-11-09 16:09:14

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

我有一个我试图查询的XML字段。我想出了如何返回第一项,第二项等。我需要弄清楚如何根据日期过滤器返回项目。日期包含在XML字段中,但我无法确定格式。以下是名为[AMOUNT]的XML字段示例。

<X C="1" I="0">
  <E D="0Y56M0W0D" P="0" A="122039" />
  <E D="0Y10M0W0D" P="0" A="125739" />
  <E D="1000Y0M0W0D" P="1" A="131739" />
</X>

我可以使用以下查询来查询指定要返回的项目。

SELECT 
 cast(AMOUNT as XML).value('(/X/E)[1]/@A','varchar(10)') AS [TEST],
 cast(AMOUNT as XML).value('(/X/E)[2]/@A','varchar(10)') AS [TEST2],
 cast(AMOUNT as XML).value('(/X/E)[3]/@A','varchar(10)') AS [TEST3]
FROM MEASURE

我需要帮助找到一种方法来返回在特定日期生效的[AMOUNT],让我们说2016-11-01。下面是前端显示数据的内容。还有一个[STARTDATE]字段,在这种情况下它等于2012-01-01。

DATE       | MONTH | AMOUNT |
2012-01-01 |      1|  122039|
2016-09-01 |     57|  125739|
2017-07-01 |     67|  131739|

我需要帮助编写查询以拉出[AMOUNT] 125,739作为2016-11-01的日期过滤器。任何帮助将不胜感激。我使用的是SQL Server 2008。

1 个答案:

答案 0 :(得分:1)

这似乎是问题的解决方案这是如何解释的?但尚未解决实际问题我应该如何在过滤器中使用它?。一旦您了解了如何阅读本文,您是否需要帮助?

DECLARE @d1 DATETIME={d'2012-01-01'};
DECLARE @d2 DATETIME=(SELECT DATEADD(MONTH,56,@d1));
DECLARE @d3 DATETIME=(SELECT DATEADD(MONTH,10,@d2));

SELECT @d1,@d2,@d3;

字符串 D =&#34; 0Y56M0W0D&#34; 似乎将 D 指向下一个日期。 字符串 D =&#34; 0Y10M0W0D&#34; 是以下的 D ,并且 D =&#34; 1000Y0M0W0D 指向我是最后一个,因为没有人在困扰1000年后发生的事情!

更新:一个完整​​的例子

一些提示

  • 第一个CTE逐行读取XML并返回派生表。
  • 使用CHARINDEXSUBSTRING可以选择字母 Y,M,W和D 之间的数字。
  • 金额除以1000并转换为decimal

当您使用SQL-Server 2008时,您无法使用累积SUM() OVER(),这就是为什么我使用递归CTE遍历您的日期并将距离添加到上一行的日期。

试试这个:

DECLARE @xml XML=
N'<X C="1" I="0">
  <E D="0Y56M0W0D" P="0" A="122039" />
  <E D="0Y10M0W0D" P="0" A="125739" />
  <E D="1000Y0M0W0D" P="1" A="131739" />
</X>';

DECLARE @StartDate DATETIME={d'2012-01-01'};

- 这是第一次CTE

WITH Shredded AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS SortNr
          ,D.Dist AS Distance
          ,e.value('@P','int') AS P
          ,CAST(e.value('@A','int') AS DECIMAL(10,4))/1000 AS Amount
          ,CAST(SUBSTRING(D.Dist,1,PosY-1) AS INT) AS Y
          ,CAST(SUBSTRING(D.Dist,PosY+1,PosM-PosY-1) AS INT) AS M
          ,CAST(SUBSTRING(D.Dist,PosM+1,PosW-PosM-1) AS INT) AS W
          ,CAST(SUBSTRING(D.Dist,PosW+1,PosD-PosW-1) AS INT) AS D
    FROM  @xml.nodes('/X/E') AS A(e)
    CROSS APPLY (SELECT e.value('@D','nvarchar(100)') AS Dist) AS D
    CROSS APPLY(SELECT CHARINDEX('Y',D.Dist) AS PosY
                      ,CHARINDEX('M',D.Dist) AS PosM
                      ,CHARINDEX('W',D.Dist) AS PosW
                      ,CHARINDEX('D',D.Dist) AS PosD
    ) AS Positions
)

- 递归CTE

,RecCTE AS
(
    SELECT @StartDate AS ActualDate,*
    FROM Shredded
    WHERE SortNr=1

    UNION ALL

    SELECT DATEADD(YEAR,r.Y,DATEADD(MONTH,r.M,DATEADD(WEEK,r.W,DATEADD(DAY,r.D,r.ActualDate))))
          ,s.*
    FROM RecCTE AS r
    INNER JOIN Shredded AS s ON s.SortNr=r.SortNr+1
)

- 最后的查询

SELECT * FROM RecCTE

+-------------------------+--------+-------------+---+---------------+------+----+---+---+
| ActualDate              | SortNr | Distance    | P | Amount        | Y    | M  | W | D |
+-------------------------+--------+-------------+---+---------------+------+----+---+---+
| 2012-01-01 00:00:00.000 | 1      | 0Y56M0W0D   | 0 | 122.039000000 | 0    | 56 | 0 | 0 |
+-------------------------+--------+-------------+---+---------------+------+----+---+---+
| 2016-09-01 00:00:00.000 | 2      | 0Y10M0W0D   | 0 | 125.739000000 | 0    | 10 | 0 | 0 |
+-------------------------+--------+-------------+---+---------------+------+----+---+---+
| 2017-07-01 00:00:00.000 | 3      | 1000Y0M0W0D | 1 | 131.739000000 | 1000 | 0  | 0 | 0 |
+-------------------------+--------+-------------+---+---------------+------+----+---+---+