如何有条件地调整后续行的日期

时间:2014-03-17 10:38:57

标签: sql sql-server

我有一个需要报告房屋状况的系统。如果房子没有通过主要的房屋标准,房子将无法通过住房标准。元素或积累2个次要元素时。这是一个可以粘贴到管理工作室并运行的示例 - 使用注释来解释我想要实现的目标:

WITH T1 AS
( SELECT
    1 propertyid,
    'Principal roof covering' text,
    0 isprimary,
    CAST('1 Apr 2016' AS datetime) date,
    'This should not appear because it is secondary and 
    there are no subsequent secondary elements for this property' comment 
    UNION SELECT
    1,
    'Chimney stacks',
    0,
    CAST('1 Apr 2015' AS datetime),
    'This should appear unadjusted because it is secondary and there is a 
    preceding secondary element for the same property' UNION SELECT
    1,
    'Bathroom condition',
    1,
    CAST('1 Apr 2014' AS datetime),
    'This should appear unadjusted because it is primary' UNION SELECT
    2,
    'Damp proof course',
    0,
    CAST('1 Apr 2016' AS datetime),
    'This should not appear because it is secondary and there are no
    subsequent secondary elements for this property' 
    UNION SELECT
    1,
    'External wall finish',
    0,
    CAST('1 Apr 2014' AS datetime),
    'This should get it''s date adjusted to 2015 because it is secondary 
    and the next secondary element is in 2015' UNION SELECT
1,
'Flashings',
0,
CAST('1 Jun 2015' AS datetime),
'This should get it''s date adjusted to Sep 2015 because it is secondary 
    and the next secondary element is in  Sep 2015' UNION SELECT
1,
'Underground drainage',
0,
CAST('1 Sep 2015' AS datetime),
'This should appear unadjusted because it is secondary and there is a 
    preceding secondary element for the same property'
)
SELECT
    *
FROM t1
ORDER BY date

如何过滤掉不具有后续辅助元素的辅助元素,并调整后续元素作为后续元素日期的元素的日期?

2 个答案:

答案 0 :(得分:1)

请看这个:

    SELECT t1.*
    ,CASE 
        WHEN (t1.isprimary = 1)
            OR (
                t1.isprimary = 0
                AND Post.DATE IS NULL
                )
            THEN T1.DATE
        ELSE Post.DATE
        END AS Date_Corrected
FROM t1
CROSS APPLY (
    SELECT TOP (1) t2.DATE
    FROM T1 t2
    WHERE T2.propertyid = t1.propertyid
        AND t2.DATE > t1.DATE
        AND t2.isprimary = 0
        ORDER BY t2.date
    ) Post
OUTER APPLY (
    SELECT TOP (1) t2.DATE
    FROM T1 t2
    WHERE T2.propertyid = t1.propertyid
        AND t2.DATE < t1.DATE
        AND t2.isprimary = 0
        order by t2.date DESC
    ) Pres
ORDER BY t1.DATE

答案 1 :(得分:1)

以下查询应返回您想要的内容:

WITH T1 AS
( 

    SELECT * 
        , ROW_NUMBER() OVER (PARTITION BY propertyid, isprimary ORDER BY date) AS PropNo
        , COUNT(*) OVER (PARTITION BY propertyid, isprimary) AS PropCount
    FROM 
        -- Replace below with your source data table
         (VALUES(1,'Bathroom condition',1,'2014-04-01')
        ,(1,'External wall finish',0,'2014-04-01') 
        ,(1,'Chimney stacks',0,'2015-04-01') 
        ,(1,'Principal roof covering',0,'2016-04-01') 
        ,(2,'Damp proof course',0,'2016-04-01')) T(propertyid, text, isprimary, date)
)
SELECT 
      T1.propertyid
    , T1.text
    , T1.isprimary
    , CASE 
          WHEN T1.isprimary = 1 OR T1.PropNo = T1.PropCount - 1 THEN T1.date
          ELSE ISNULL(T1Next.date, T1.date) END AS [date]
FROM T1 
LEFT JOIN T1 AS T1Next ON T1.propertyid = T1Next.propertyid 
    AND T1.isprimary = T1Next.isprimary
    AND T1.PropNo = T1Next.PropNo - 1
WHERE T1.isprimary = 1
    OR (T1.PropNo < T1.PropCount)

我使用ROW_NUMBER()和COUNT(*)函数来确定何时有后续行。要应用后续行中的日期,我使用LEFT JOIN。

修改 将左连接更改为此连接可确保连接仅在辅助元素上发生,并且仅在每个第二个元素上发生:

LEFT JOIN T1 AS T1Next ON T1.propertyid = T1Next.propertyid 
    AND T1.isprimary = 0
    AND T1Next.isprimary = 0
    AND T1.PropNo = T1Next.PropNo - 1
    AND T1Next.PropNo % 2 = 0

这意味着我们不需要案例陈述,只需这样:

ISNULL(T1Next.date, T1.date) AS [date]

但是where声明并不完全正确。这有效:

WHERE T1.isprimary = 1
    OR (T1.PropNo % 2 = 0)     --every 2nd one
    OR T1Next.date IS NOT NULL --and the 1st if there is a 2nd