ID过滤基于单个日期字段,没有结束日期

时间:2018-04-11 21:10:59

标签: sql sql-server sql-server-2012 window-functions

类别

+----+--------+----------+------------+
| ID | Active | Category | Effective  |
+----+--------+----------+------------+
|  1 | FALSE  | A        | 1/29/2009  |
|  1 | FALSE  | B        | 5/13/2014  |
|  1 | TRUE   | B        | 9/21/2017  |
|  2 | FALSE  | B        | 3/4/2010   |
|  2 | TRUE   | A        | 2/19/2016  |
|  3 | FALSE  | A        | 10/15/2015 |
|  3 | TRUE   | B        | 8/12/2017  |
+----+--------+----------+------------+

运行时

+----+------------+
| ID |  RunDate   |
+----+------------+
|  1 | 6/14/2015  |
|  1 | 9/14/2015  |
|  1 | 10/4/2016  |
|  2 | 5/1/2014   |
|  2 | 9/21/2016  |
|  3 | 3/12/2016  |
|  3 | 12/14/2017 |
+----+------------+

我正在尝试仅选择那些有{rundate}的ID,而Category A是有效的时间点。所以ID 1不应该在输出中,因为即使它有A类,它的rundate也是在B类生效之后。

预期产出

+----+
| ID |
+----+
|  2 |
|  3 |
+----+

尝试:

SELECT DISTINCT
    RT.ID
FROM Category C
INNER JOIN Runtime RT
    ON C.ID=RT.ID
WHERE 1=1
    AND C.Category='A'
    AND RT.rundate >= C.effective
ORDER BY RT.ID 

然而,这并不考虑中间变化,只是根据每个ID的任何有效日期是否在该日期之前选择结果

2 个答案:

答案 0 :(得分:0)

- 请尝试此查询

;with cte_category(Id, Effective,Rundate)
AS
(
SELECT c.id, max(c.effective)effective, max(r.rundate)rundate
FROM Category c
INNER JOIN runtime r on r.id = c.id
WHERE r.rundate>c.effective
GROUP BY c.id
)
SELECT DISTINCT t1.id
FROM cte_category t1
INNER JOIN cte_category t2 
    ON t1.id > t2.Id
    AND t2.Effective < t1.Rundate
ORDER BY t1.ID

答案 1 :(得分:0)

样本数据准备

declare @category table ( ID int, Active varchar(10), Category char(1), Effective date)
insert into @category
values (1, 'FALSE', 'A', '20090129')
    , (1, 'FALSE', 'B', '20140513'), (1, 'TRUE ', 'B', '20170921')
    , (2, 'FALSE', 'B', '20100304'), (2, 'TRUE ', 'A', '20160219')
    , (3, 'FALSE', 'A', '20151015'), (3, 'TRUE ', 'B', '20170812')

    , (4, 'FALSE', 'B', '20151015'), (4, 'FALSE ', 'A', '20170812')
    , (4, 'True ', 'A', '20180812')
    , (3, 'TRUE ', 'A', '20270812')

declare @runtime table (ID int, RunDate date)
insert into @runtime
values (1, '20150614')
    , (1, '20150914'), (1, '20161004'), (2, '20140501')
    , (2, '20160921'), (3, '20160312'), (3, '20171214')

我认为您的主要问题是具有相同值的连续类别。您需要对这些值进行分组,并找到每个此类组的最小生效日期。这是cte部分所做的。然后只需连接两个表来获得预期的输出。

;with cte as (
    select
        ID, Category, Effective = min(Effective)
        , EndDate = isnull(lead(min(Effective)) over (partition by ID order by min(Effective)), '99991231')
    from (
        select 
            *, grp = row_number() over (partition by ID order by Effective)
            - row_number() over (partition by ID, Category order by Effective)
        from 
            @category
    ) t
    group by ID, Category, grp
)

select
    r.ID
from
    @runtime r
    join cte c on r.ID = c.ID and r.RunDate >= c.Effective and r.RunDate < c.EndDate
where
    c.Category = 'A'