在我的项目中,我有一个用户电子邮件表EMAILS:
| ID | PROFILE_ID | EMAIL | LAST_UPDATED_TIMESTAMP|
___________________________________________________________________
| 1| 1| a@a.com| 2017-02-02 15:13:46|
| 2| 1| b@b.com| 2017-02-01 15:13:46|
| 3| 2| c@c.com| 2017-02-03 15:13:46|
其中PROFILE_ID指的是用户配置文件表PROFILES。我想为每个用户个人资料获得2个(一般为N个)最新的不同电子邮件作为一行:
| PROFILE_ID | EMAIL_1 | EMAIL_2 |
__________________________________________________
| 1| b@b.com| a@a.com|
| 2| c@c.com| NULL|
我尝试了很多查询,我停下来的最后一个查询如下:
SELECT
EMAIL1.PROFILE_ID,
EMAIL1.EMAIL AS EMAIL_1,
EMAIL2.EMAIL AS EMAIL_2
FROM EMAILS EMAIL1
LEFT JOIN
EMAILS EMAIL2
ON EMAIL1.PROFILE_ID = EMAIL2.PROFILE_ID AND EMAIL2.LAST_UPD_TMST <= EMAIL1.LAST_UPD_TMST AND EMAIL1.ID <> EMAIL2.ID
但它为我提供了包含多封电子邮件的个人资料的额外记录:
| PROFILE_ID | EMAIL_1 | EMAIL_2 |
__________________________________________________
| 1| b@b.com| a@a.com|
| 1| a@a.com| NULL|
| 2| c@c.com| NULL|
我使用Oracle 11g,但如果可能的话,请记住MySql兼容性。有人可以说上面提到的查询有什么问题吗?
答案 0 :(得分:2)
在Oracle 11中,您可以使用PIVOT运算符。我不了解MySQL,但我相信它没有PIVOT运营商。
with
test_data ( ID, PROFILE_ID, EMAIL, LAST_UPDATED_TIMESTAMP ) as (
select 1, 1, 'a@a.com', to_timestamp('2017-02-02 15:13:46', 'yyyy-mm-dd hh24:mi:ss')
from dual union all
select 2, 1, 'b@b.com', to_timestamp('2017-02-01 15:13:46', 'yyyy-mm-dd hh24:mi:ss')
from dual union all
select 3, 2, 'c@c.com', to_timestamp('2017-02-03 15:13:46', 'yyyy-mm-dd hh24:mi:ss')
from dual
)
-- end of test data (not part of the solution); SQL query begins BELOW THIS LINE
select profile_id, email_1, email_2
from ( select profile_id, email,
row_number() over (partition by profile_id
order by last_updated_timestamp desc) as rn
from test_data
)
pivot (min(email) for rn in (1 as email_1, 2 as email_2))
;
PROFILE_ID EMAIL_1 EMAIL_2
---------- ------- -------
1 a@a.com b@b.com
2 c@c.com
2 rows selected.
答案 1 :(得分:0)
一种方法是条件聚合:
select profile_id,
max(case when seqnum = 1 then email end) as email1,
max(case when seqnum = 2 then email end) as email2
from (select e.*,
row_number() over (partition by profile_id order by last_updated_timestamp) as seqnum
from emails e
) e
group by profile_id;
如果您确实想删除重复项,则可以在row_number()
之前聚合数据。要获取上次重复发送的电子邮件:
select profile_id,
max(case when seqnum = 1 then email end) as email1,
max(case when seqnum = 2 then email end) as email2
from (select e.*,
row_number() over (partition by profile_id order by last_updated_timestamp) as seqnum
from (select profile_id, email, max(last_updated_timestamp) as last_updated_timestamp
from emails e
group by profile_id, email
) e
) e
group by profile_id;