更新
对于甲骨文:
FROM mytable t
JOIN ( SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS b
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS e
FROM DUAL
) dr
ON NOT ( t.effective_date_from >= dr.e OR t.effective_date_to < dr.b )
OR ( t.effective_date_from IS NULL AND t.effective_date_to IS NULL )
对于 MySQL:
FROM mytable t
JOIN ( SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS b
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS e
) dr
ON NOT ( t.effective_date_from >= dr.e OR t.effective_date_to < dr.b )
OR ( t.effective_date_from IS NULL AND t.effective_date_to IS NULL )
在查看slOppy的答案并再次查看问题后,我意识到您有两个日期列effective_date_from
和指定日期范围内的任何时间(上一季度初和下一季度初之间)。effective_date_to
from
to
为了简化(现在),我将只考虑有效日期的情况from < to
。
可能的情况可以这样描述(相当粗略):竖线代表drb
和dre
(日期范围开始和结束)小于号代表“ effective_date_from
”(edf
)大于号代表“ effective_date_to
”(edt
)破折号代表“有效”日期之间edf
和edt
drb dre
<---> | | case 1: edt < drb
<---|----> | case 2: drb between edf and edt
<--|-------|----> case 3: edf < drb AND edt > dre
| <---> | case 4: edf > drb AND edt < dre
| <--|---> case 5: edf between drb and dre AND edt > dre
| | <---> case 6: edf > dre
| |
<---> | case e1: edt = drb
<--|-------> case e2: edf > drb AND edt = dre
<---> | case e3: edf = drb and edt < dre
<-------> case e4: edf = drb and edt = dre
<-------|--> case e5: edf = drb and edt > dre
| <---> case e6: edf > drb AND edt = dre
| <---> case e7: edf = dre
我认为您要求返回满足案例 2 到 5 和边缘案例 e1 到 e6 的行,除了案例 1、6 和 e7 之外的所有案例。
如果我们可以编写一个谓词来测试案例 1 和 6,然后否定它,它应该给我们你想要的。像这样的东西:
要处理考虑时间分量的日期时间:
WHERE NOT ( effective_date_to < drb OR effective_date_from >= dre )
(生成的表达式drb
和dre
(日期范围开始和日期范围结束)显示在我的原始答案中。)
要同时返回effective_date_from
和effective_date_to
均为 NULL 的行,我们可以添加一个单独的条件来处理这种情况。
使用内联视图来提供这些表达式,我们得到了答案顶部的 SQL。
我之前搁置了奇怪的案例,例如effective_date_from > effective_date_to
;您必须弄清楚这些行是否有效,以及应该返回这些行的条件。
原始答案:
这可以在Oracle和MySQL中实现。我使用的方法是首先生成每个季度相对于当前日期的“开始日期”。我们可以在谓词中引用那些日期值(或返回日期值的表达式)。
要在MySQL中导出季度的“开始日期” ,我们可以使用该QUARTER()
函数。(此函数从指定的 DATE 值返回整数值 1 到 4。结合YEAR
和 MAKEDATE 函数,我们可以从当前系统日期生成每个相对季度的“开始日期”,如下所示:
SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS next_q
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-1 QUARTER AS this_q
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS prev_q
next_q this_q prev_q
---------- ---------- ------------
2013-10-01 2013-07-01 2013-04-01
一旦我们有了这些日期值,就很简单了。要仅获取特定日期列(mydate
在以下示例中)的值在上一季度或当前季度内的行,我们只需将该日期列与上面的两个表达式进行比较:
WHERE mydate >= MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER
AND mydate < MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER
在Oracle中,方法是相同的。不同之处在于我们如何得出相对季度的开始日期。在 Oracle 中,我们可以使用如下表达式:
-- ALTER SESSION SET nls_date_format = 'YYYY-MM-DD';
SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS next_q
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),0) AS this_q
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS prev_q
FROM DUAL
NEXT_Q THIS_Q PREV_Q
---------- ---------- ------------
2013-10-01 2013-07-01 2013-04-01
因此,要获取mydate
当前或上一季度的值所在的行,我们将该列与其中两个表达式进行比较:
WHERE mydate >= ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3)
AND mydate < ADD_MONTHS(TRUNC(SYSDATE,'Q'),3)
(大于或等于上一季度的开始日期,小于下一季度的开始日期)。
使用这些“开始日期”的一种稍微不同的方法是使用内联视图来返回日期值;这给了我们一个可以测试的单独查询,我们可以为表达式分配列名。在这里,我为内联视图使用别名dr
(日期范围):
甲骨文
FROM mytable t
JOIN ( SELECT ADD_MONTHS(TRUNC(SYSDATE,'Q'),3) AS bd_next_qtr
, ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3) AS bd_prev_qtr
FROM DUAL
) dr
ON t.mydate >= dr.bd_prev_qtr
AND t.mydate < dr.bd_next_qtr
MySQL
FROM mytable t
JOIN ( SELECT MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER AS bd_next_qtr
, MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER AS bd_prev_qtr
) dr
ON t.mydate >= dr.bd_prev_qtr
AND t.mydate < dr.bd_next_qtr