我有3张桌子:
Client (cus_id, First_Name)
sms_Log (sms_log_id, cus_id, sms_time)
Mail_Log (mail_Log_id, cus_id, mailed_time)
Cus_id是三个表之间的链接,但是,sms_log和Mail_Log之间没有链接导致交叉连接。我需要将邮件发送后收到的所有短信分组。
E.g。数据
Table: Client
cus_id First_Name
4 'Doe'
Table: sms_log
sms_log_id cus_id, sms_time
1 4 08/02/2012
2 4 08/03/2012
3 4 08/06/2012
Table: Mail_Log
mail_Log_id cus_id mailed_time
1 4 08/01/2012
2 4 08/05/2012
加入这些将创建一个包含6条记录的交叉连接。
有没有办法可以写一个查询,可以告诉我前面的两条短信(日期2和3)是在01号收到的邮件中收到的,而第06天的短信是为了回复05日发来的邮件?
预期输出(每封邮件收到的短信数)
Table: output_record
cus_id mail_Log_id, sms_received
4 1 2
4 2 1
答案 0 :(得分:0)
在Oracle 12.1及更高版本中,您可以使用match_recognize
子句解决此问题。
在您描述的三个表中,您不需要第一个用于"手头的问题"。如果您需要检索客户名称和其他详细信息,可以将下面的查询结果加入customer
表;我会假设你能够自己做到这一点。
然后,要从其他两个表中的输入中获取所需的摘要,您根本不需要连接。您需要一个UNION ALL(仔细完成),然后您可以使用嵌套分析函数(在早期版本的Oracle中)或使用match_recognize
一次完成所有工作,如下所示。
在WITH
子句中,我创建了测试数据,因为您没有提供它。请注意,WITH
子句不是解决方案的一部分 - 您应该将其删除,并在查询的其余部分确保表名和列名与实际输入匹配。
中间部分是两个日志表的union all
(相关列)。然后match_recognize
就在最后。它为找到的每个完整匹配产生一行 - 其中a"匹配"由一个邮件事件和随后的所有SMS事件组成,直到下一个邮件事件。所有内容首先由cus_id
分区(根据需要),每个此类分区按cus_id
按事件时间(邮寄时间或短信时间)排序。我也允许在完全相同的时间记录邮件和短信(非常罕见,但并非不可能)。在这种情况下,我会假设邮件是先发送的,所以短信属于那封邮件(而不是前一封邮件)。如果需要,这可以很容易地改变。
with
sms_log ( sms_log_id, cus_id, sms_time ) as (
select 1, 4, to_date('08/02/2012', 'mm/dd/yyyy') from dual union all
select 2, 4, to_date('08/03/2012', 'mm/dd/yyyy') from dual union all
select 3, 4, to_date('08/06/2012', 'mm/dd/yyyy') from dual
),
mail_log ( mail_Log_id, cus_id, mailed_time ) as (
select 1, 4, to_date('08/01/2012', 'mm/dd/yyyy') from dual union all
select 2, 4, to_date('08/05/2012', 'mm/dd/yyyy') from dual
)
select cus_id, mail_log_id, sms_received
from (
select cus_id, mail_log_id, mailed_time as tm
from mail_log
union all
select cus_id, null, sms_time
from sms_log
)
match_recognize(
partition by cus_id
order by tm, mail_log_id
measures m.mail_log_id as mail_log_id,
m.tm as mailed_time,
count(*) - 1 as sms_received
pattern ( m s* )
define m as mail_log_id is not null,
s as mail_log_id is null
)
order by cus_id, mailed_time
;
CUS_ID MAIL_LOG_ID SMS_RECEIVED
------ ----------- ------------
4 1 2
4 2 1