标记列基于每2个月不同行的最小(日期)

时间:2017-06-24 03:16:04

标签: sql oracle date oracle11g

我有一张这样的表,有不同的投诉信息

telephone   motive  complaint_id    complaint_date
980761524   motive1 R1234561        23/05/2017
980761524   motive1 R1234562        23/05/2017
980761524   motive1 R1234563        25/08/2017
980761524   motive1 R1234564        26/09/2017
980761524   motive1 R1234565        10/10/2017
980761524   motive1 R1234566        30/12/2017
991761525   motive2 R4454222        24/06/2017
991761525   motive2 R4454223        29/06/2017
991761525   motive2 R4454224        30/10/2017
940789563   motive3 R8993271        24/06/2017
940789563   motive3 R8993272        29/06/2017
940789563   motive3 R8993273        30/10/2017

我需要编写一个查询(oracle-sql),用一个具有相同电话的投诉的repeat_flag(新列)标记,同样的动机,min(complaint_date)为0但是这个min (complaint_date)每2个monhts更改一次。

让我详细解释一下。

所以,让我们说我正在分析第一组电话/动机

telephone  motive  complaint_id    complaint_date
980761524   motive1 R1234561        23/05/2017
980761524   motive1 R1234562        23/05/2017
980761524   motive1 R1234563        25/08/2017
980761524   motive1 R1234564        26/09/2017
980761524   motive1 R1234565        10/10/2017
980761524   motive1 R1234566        30/12/2017

此组的分钟(complaint_date)为23/05/2017,此处有2行具有相同的日期。因此,为了只留下一个,我转到专栏complaints_id查看生成的第一个投诉。所有的投诉_都是R+Number,最低的数字是第一个投诉(R1234561),并将其标记为0。因此,如果下一行的日期是第一分钟内的2个月(complaint_date),我将其标记为1.

如果下一个抱怨日期在两个月之内,那么您会重复投诉,并将其标记为1.在此示例中,23/05/2017位于其中,因此我将其标记为1.

如果下一个投诉日期不在两个月之内,则不再重复,并将其标记为“0”' 0。现在,此处的抱怨日期为25/08/2017,现在这是新分钟(complaint_date)

下一行,这里我得到了26/09/2017,这是2个月25/08/2017所以这是重复,我将其标记为1.

下一行,这里我得到了10/10/2017,这是2个月25/08/2017所以这是重复,我将其标记为1.

最后,在这里我得到30/12/2017不到2个月25/08/2017所以这不重复,我将其标记为。现在这是新的 min(complaint_date)

进一步的行相同。

最终结果应如下所示

telephone   motive  complaint   complaint_date  2months_repeat_flag
980761524   motive1 R1234561        23/05/2017                   0
980761524   motive1 R1234562        23/05/2017                   1
980761524   motive1 R1234563        25/08/2017                   0
980761524   motive1 R1234563        26/09/2017                   1
980761524   motive1 R1234563        10/10/2017                   1
980761524   motive1 R1234563        30/12/2017                   0

决赛桌应该是这样的

telephone   motive  complaint   complaint_date  2months_repeat_flag
980761524   motive1 R1234561        23/05/2017                    0
980761524   motive1 R1234562        23/05/2017                    1
980761524   motive1 R1234563        25/08/2017                    0
980761524   motive1 R1234564        26/09/2017                    1
980761524   motive1 R1234565        10/10/2017                    1
980761524   motive1 R1234566        30/12/2017                    0
991761525   motive2 R4454222        24/06/2017                    0
991761525   motive2 R4454223        29/06/2017                    1
991761525   motive2 R4454224        30/10/2017                    0
940789563   motive3 R8993271        24/06/2017                    0
940789563   motive3 R8993272        29/06/2017                    1
940789563   motive3 R8993273        30/10/2017                    0

我的桌子有大约2到30个投诉,使用相同的电话和相同的动机。

只用SQL可以吗?欢迎任何存储过程。但我更喜欢只使用SQL来执行此操作,因为我的用户无权创建sp。

4 个答案:

答案 0 :(得分:4)

这是一个适用于Oracle 10及更高版本的解决方案。它使用model子句(match_recognize子句的远端祖先)。 Oracle 12及更高版本中提供的match_recognize可能要快几倍,但可能不适用于OP(问题标记为oracle11g)。

<强>设置

alter session set nls_date_format = 'dd/mm/yyyy';

create table test_data ( telephone, motive, complaint_id, complaint_date ) as
    select 980761524, 'motive1', 'R1234561', to_date('23/05/2017') from dual union all
    select 980761524, 'motive1', 'R1234562', to_date('23/05/2017') from dual union all
    select 980761524, 'motive1', 'R1234563', to_date('25/08/2017') from dual union all
    select 980761524, 'motive1', 'R1234564', to_date('26/09/2017') from dual union all
    select 980761524, 'motive1', 'R1234565', to_date('10/10/2017') from dual union all
    select 980761524, 'motive1', 'R1234566', to_date('30/12/2017') from dual union all
    select 991761525, 'motive2', 'R4454222', to_date('24/06/2017') from dual union all
    select 991761525, 'motive2', 'R4454223', to_date('29/06/2017') from dual union all
    select 991761525, 'motive2', 'R4454224', to_date('30/10/2017') from dual union all
    select 940789563, 'motive3', 'R8993271', to_date('24/06/2017') from dual union all
    select 940789563, 'motive3', 'R8993272', to_date('29/06/2017') from dual union all
    select 940789563, 'motive3', 'R8993273', to_date('30/10/2017') from dual
;

commit;

<强>查询

select telephone, motive, complaint_id, complaint_date, flag
from   test_data
model  
  partition by (telephone, motive)  
  dimension by (row_number() over (partition by telephone, motive 
                                   order by     complaint_date, complaint_id) rn)
  measures (complaint_id, complaint_date, complaint_date s, 0 flag)  
  rules (  
    s[rn>1]    = case when complaint_date[cv(rn)] < add_months(s[cv(rn) - 1], 2)  
                      then s[cv(rn) - 1]  
                      else complaint_date[cv(rn)]  
                 end,
    flag[rn>1] = case when s[cv(rn)] = s[cv(rn) - 1] then 1 else 0 end
  )
order by telephone, motive, rn
;

输出 :(通过电话订购,然后按动机订购 - 可根据需要进行更改)

 TELEPHONE   MOTIVE    COMPLAINT_ID COMPLAINT_DATE FLAG
 ---------   -------   ------------ -------------- ----
 940789563   motive3   R8993271     24/06/2017        0
 940789563   motive3   R8993272     29/06/2017        1
 940789563   motive3   R8993273     30/10/2017        0
 980761524   motive1   R1234561     23/05/2017        0
 980761524   motive1   R1234562     23/05/2017        1
 980761524   motive1   R1234563     25/08/2017        0
 980761524   motive1   R1234564     26/09/2017        1
 980761524   motive1   R1234565     10/10/2017        1
 980761524   motive1   R1234566     30/12/2017        0
 991761525   motive2   R4454222     24/06/2017        0
 991761525   motive2   R4454223     29/06/2017        1
 991761525   motive2   R4454224     30/10/2017        0

答案 1 :(得分:3)

另一种解决方案基于递归CONNECT BY子句

SELECT t.*,
       CASE WHEN t1.complaint_id IS NULL
       THEN 1 ELSE 0 
       END As two_months_repeat_flag
FROM test_data t
LEFT JOIN (
    SELECT complaint_id
    FROM (
        select t.complaint_id,
               (
                 SELECT min( complaint_id ) KEEP (DENSE_RANK FIRST ORDER BY complaint_date, complaint_id )
                 FROM test_data t1
                 WHERE t1.telephone = t.telephone
                   AND t1.motive = t.motive 
                   AND t1.complaint_date > add_months( t.complaint_date, 2 )
               ) as next_complaint_id,
               row_number() over (partition by telephone, motive order BY complaint_date, complaint_id) as rn
        from test_data t
    )
    start with rn = 1
    connect by complaint_id = prior next_complaint_id
) t1
ON t.complaint_id = t1.complaint_id
ORDER BY 1, 2,4,3
 TELEPHONE MOTIVE  COMPLAIN COMPLAINT_ TWO_MONTHS_REPEAT_FLAG
---------- ------- -------- ---------- ----------------------
 940789563 motive3 R8993271 24/06/2017                      0
 940789563 motive3 R8993272 29/06/2017                      1
 940789563 motive3 R8993273 30/10/2017                      0
 980761524 motive1 R1234561 23/05/2017                      0
 980761524 motive1 R1234562 23/05/2017                      1
 980761524 motive1 R1234563 25/08/2017                      0
 980761524 motive1 R1234564 26/09/2017                      1
 980761524 motive1 R1234565 10/10/2017                      1
 980761524 motive1 R1234566 30/12/2017                      0
 991761525 motive2 R4454222 24/06/2017                      0
 991761525 motive2 R4454223 29/06/2017                      1
 991761525 motive2 R4454224 30/10/2017                      0

12 rows selected. 

答案 2 :(得分:0)

或者您可以使用Oracle的LAG功能,让您可以访问上一行的值:

 SELECT telephone,
        motive,
        complaint_id,
        complaint_date,
        CASE WHEN 
           ADD_MONTHS(LAG  (complaint_date, 1 , NULL) 
                        OVER (PARTITION BY  telephone, motive 
                              ORDER BY complaint_date),2) > complaint_date   
             THEN 1 ELSE 0  END AS flag
   FROM test_data

此解决方案假设您希望自上次投诉以来存在差异 - 而不是第一次投诉。

答案 3 :(得分:0)

对于Oracle 12.1及更高版本,这是一个使用IFileOperation子句的解决方案。 OP应该尝试各种解决方案(无论如何解决问题的解决方案),看看哪个解决方案对他/她的具体数据最有效。

match_recognize