我有一张这样的表,有不同的投诉信息
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。
答案 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