如何使用SQL从数据库中选择最近2个季度的数据?

Raj*_*shi 2 mysql sql oracle toad mysqldump

我在我们的数据库中有过去两年的模型数据.我想从数据库表中仅选择最后2个季度的那些模型.

假设, Sysdate-> 29/07/2013(July)

我应该能够从下面的季度检索模型

Q1-April,May,June(last quarter)

Q2-July,Aug,Sep(Including quarter)
Run Code Online (Sandbox Code Playgroud)

以下查询如何更改?

Select model_id,model_name,Effective_date_from,effective_date_to 
from   model 
where active='YES';
Run Code Online (Sandbox Code Playgroud)

spe*_*593 6

UPDATE

对于Oracle:

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 )
Run Code Online (Sandbox Code Playgroud)

对于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 )
Run Code Online (Sandbox Code Playgroud)

在回顾了slOppy的答案并再次回顾了问题之后,我意识到你有两个日期列,effective_date_from并且effective_date_to我没有考虑到你可能想要检索行和日期值之间的任何时间点的行指定日期范围内的任何时间(上一季度开始到下一季度开始之间).fromto

为了简化(现在),我将仅考虑生效日期的情况from < to.

可能的情况可以描述(相当粗略)像这样:垂直条代表drbdre(日期范围开始和结束)小于标志代表" 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
Run Code Online (Sandbox Code Playgroud)

我想你要求返回满足案例2到5以及边缘情况e1到e6的行,这是案例1,6和e7的所有情况除外.

如果我们可以编写一个测试案例1和6的谓词,然后否定它,那么它应该给我们你想要的东西.像这样的东西:

要处理考虑时间组件的日期时间:

  WHERE NOT ( effective_date_to < drb OR effective_date_from >= dre )
Run Code Online (Sandbox Code Playgroud)

(生成的表达式drbdre(日期范围开始和日期范围结束)显示在我的原始答案中.)

为了还回哪里都行effective_date_from,并effective_date_to为NULL,我们可以添加一个单独的条件来处理这种情况.

使用内联视图提供这些表达式,我们将SQL放在答案的顶部.

我以前搁置了古怪的案例,比如effective_date_from > effective_date_to; 你必须弄清楚这些行是否有效,以及应该返回那些行的条件.


原始答案:

这可以在OracleMySQL中实现.我使用的方法是首先生成每个季度的"开始日期",相对于当前日期.我们可以在谓词中引用那些日期值(或返回日期值的表达式).

要在MySQL中导出四分之一的"开始日期" ,我们可以使用该QUARTER()函数.(此函数从指定的DATE值返回1到4的整数值.结合YEARMAKEDATE函数,我们可以生成当前系统日期的每个相对季度的"开始日期",如下所示:

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  
Run Code Online (Sandbox Code Playgroud)

一旦我们有了这些日期值,它就很简单了.要仅获取特定日期列(mydate在以下示例中)具有属于上一个或当前季度的值的行,我们只是将该日期列与上面的两个表达式进行比较:

WHERE mydate >= MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-2 QUARTER
  AND mydate <  MAKEDATE(YEAR(NOW()),1) + INTERVAL QUARTER(NOW())-0 QUARTER
Run Code Online (Sandbox Code Playgroud)

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  
Run Code Online (Sandbox Code Playgroud)

因此,要获取值mydate在当前或上一季度的行,我们将该列与其中两个表达式进行比较:

WHERE mydate >= ADD_MONTHS(TRUNC(SYSDATE,'Q'),-3)
  AND mydate <  ADD_MONTHS(TRUNC(SYSDATE,'Q'),3)
Run Code Online (Sandbox Code Playgroud)

(大于或等于上一季度的开始日期,并且小于下一季度的开始日期).


使用这些"开始日期"的略有不同的方法是使用内联视图来返回日期值; 这为我们提供了一个可以测试的单独查询,我们可以为表达式分配列名.在这里,我使用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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)