【发布时间】:2018-04-11 21:10:59
【问题描述】:
表格类别
+----+--------+----------+------------+
| 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 |
+----+------------+
我试图只选择那些有运行日期的IDs,而Category A 是有效的时间点。所以ID 1 不应该出现在输出中,因为即使它有 A 类,它的运行日期也是在 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 的任何生效日期是否早于运行日期来选择结果
【问题讨论】:
-
简而言之,您似乎想在类别表上使用交叉应用(例如
cross apply (select top 1 c2.effective from category as c2 where c2.id = c.id and c2.effective > c.effective and c2.category != 'a' order by c2.effective) as c2)然后执行附加子句(where rt.rundate <= c2.effective)或类似的东西。使用自联接而不是交叉应用可以达到同样的效果,但您必须应用类似row_number()窗口函数的东西并只选择第一个结果。 -
您也可以使用
LEAD()窗口函数(因为即使下一行也是“A”,也不会有太大区别)。例如select distinct rt.id from (select *, nextEffective = lead(effective) over (partition by id order by effective) from category) as c... and rt.rundate >= c.effective and (c.nextEffective is null or rt.rundate <= c.nextEffective)...
标签: sql sql-server sql-server-2012 window-functions