2017-08-31 154 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 
; 
相關問題