2017-03-01 50 views
2

我有一個如下所示的數據集: example data set如何使用max()函數檢索使用SQL/PostgreSQL的最新行

在一個域下有多個用戶。我只需要每個email_domain一行,並且該行應該對應於max(last_login)值。總之,我只希望來自最後一個email_domain的用戶在同一個域中的所有用戶中登錄。

我用盡查詢,看起來像這樣

select * 
FROM 
(
select LOWER(SUBSTRING(ua.email FROM POSITION ('@' IN ua.email) + 1)) AS email_domain, last_login, last_name, first_name, email, phone 
from user_with_address ua 
order by email_domain 
) as A 
group by email_domain, last_login, last_name, first_name, email, phone 
having last_login = max(last_login) 
order by email_domain 

我仍然可以爲每個郵件域的多個值,我究竟做錯了名單?請幫忙。

聲明:我有SQL的基本 - >中級知識。

+0

你正在按last_login分組,可能是想選擇max(last_login)而不是按它分組?同時按名稱,電子郵件,電話等分組將記錄從域中分離出來。 –

回答

2

使用distinct on()

select distinct on (email_domain) * 
FROM (
    select lower(split_part(email, '@', 2)) AS email_domain, 
     last_login, 
     last_name, 
     first_name, 
     email, 
     phone 
    from user_with_address 
) as A 
order by email_domain, last_login desc; 

我也納入帕特里克建議簡化表達式提取從電子郵件域。

+0

謝謝!這工作完美,由last_login desc排序,並選擇使用不同的第一行。 –

0

一個選項是使用ROW_NUMBER()並保留每組相同電子郵件域記錄的最新登錄記錄。

SELECT t.email_domain, t.last_login, t.last_name, t.first_name, t.email, t.phone 
FROM 
(
    SELECT a.*, 
      ROW_NUMBER() OVER (PARTITION BY a.email_domain ORDER BY a.last_login DESC) rn 
    FROM 
    (
     SELECT LOWER(SUBSTRING(ua.email FROM POSITION ('@' IN ua.email) + 1)) AS email_domain, 
       last_login, last_name, first_name, email, phone 
     FROM user_with_address ua 
    ) a 
) t 
WHERE t.rn = 1 
ORDER BY t.email_domain 

請注意,我實際上在這裏子查詢兩次,以避免重複計算電子郵件域的代碼。如果不是這樣,我們可以用一個子查詢來完成。我們可以在這裏使用一個子查詢,但查詢會更難閱讀。

+0

使用'split_part(ua.email,'@',2)'而不是'substring(ua.email FROM position(...)+ 1)''。 – Patrick

+0

謝謝。這更有意義,更簡單。 –

0

我喜歡Tim Biegeleisen的回答,但這更簡單一些,SQL明智。雖然不知道性能差異。

select 
    LOWER(SUBSTRING(ua.email FROM POSITION ('@' IN ua.email) + 1)) AS email_domain, 
    last_login, 
    last_name, 
    first_name, 
    email, 
    phone 
from user_with_address ua 
where last_login = (select max(last_login) 
        from user_with_address ua2 
        where LOWER(SUBSTRING(ua.email FROM POSITION ('@' IN ua.email) = 
          LOWER(SUBSTRING(ua2.email FROM POSITION ('@' IN ua2.email)) 
order by email_domain;