2017-08-31 69 views
0

我想根据以下规则为每个用户选择一个电子邮件地址。 如果preferred_email为Y,请选择该电子邮件地址([email protected])。 如果preferred_email不是Y,请使用该电子邮件地址。 某些用户可能只有一个preferred_email值为N. 我试过使用case语句,但它没有返回正确的结果。为每个用户选择一个电子邮件地址

这是表格的一个例子。

user_id email_address  preferred_email 
25  [email protected] N 
25  [email protected] Y 
26  [email protected] N 
27  [email protected] N 
+0

那么,什么是所需的输出? [email protected]所有3个user_ids?或[email protected]分别为user_id#25和[email protected]和[email protected]分别为#26和#27? –

+0

您使用的是哪个版本的Oracle?不同的版本附带不同的工具,可用于top-n(最大n组)问题。 – mathguy

回答

2
SELECT user_id, 
     MAX(email_address) KEEP (DENSE_RANK FIRST ORDER BY preferred_email DESC, ROWNUM) 
     AS email_address 
FROM your_table 
GROUP BY user_id 

SELECT user_id, 
     email_address 
FROM (
    SELECT t.*, 
     ROW_NUMBER() OVER (PARTITION BY user_id 
          ORDER BY preferred_email DESC, ROWNUM) 
      AS rn 
    FROM your_table t 
) 
WHERE rn = 1; 
+0

在这两种解决方案中的'ORDER BY'子句中都不需要'ROWNUM';如果至少有一个首选电子邮件地址,则会选择其中一个基本随机的电子邮件地址(在ORDER BY子句中有或没有'ROWNUM'),如果不是,将会选择一个来自所有电子邮件地址的基本上随机的地址。 'max(email_address)'在这种情况下与随机相同。 – mathguy

0

在Oracle 12.1和更高,这可以很容易地与match_recognize子句完成的,这样的:

select user_id, email_address 
from inputs 
match_recognize (
    partition by user_id 
    order by preferred_email desc nulls last 
    all rows per match 
    pattern (^x) 
    define x as 0 = 0 
) 
; 

然而,这种解决方案(如以及其他一些人在这里提出的)有一个潜在的弱点:它依赖于明确的排序'Y' vs 'N',并且它假设这些是preferred_email列中唯一可能的值(并且该列不可为空)。

这将是更好,如果列preferred_email并不受限于非可空,只可能值'Y''N',有像

order by case preferred_email when 'Y' then 0 end [...] 

不幸的是订单子句,match_recognize子句只能按列顺序,而不是表达式。 (希望将来能够解决这个问题!)在这种情况下,使用FIRST/LAST聚合函数的集合解决方案(如MT0的答案)是最佳选择 - 但ORDER BY子句会相应更改。

select user_id, 
     max(email_address) keep (dense_rank first 
       order by case preferred_email when 'Y' then 0 end) as email_address 
from  inputs 
group by user_id 
; 
相关问题