2014-06-29 51 views
0

我有一個包含姓名和出生日期的表格。
我想獲得與下一個即將到來的生日相對應的名字。 (其中n是一個整數)
這不是通過使用LIMIT(我不想限制行數),既不使用BETWEEN或WHERE子句,因爲它沒有在有限的時間內。
感謝的對你有所幫助MYSQL - 即將到來的X出生日期

+1

我也不太明白,如果n是要返回即將到來的出生日期的數字,是不是基本上限制了返回的行數?我理解你的問題是這樣的:得到[即將返回的日期]即將到來的出生日期。 – wribit

+0

當然可以用LIMIT。你只需要先刪除重複(提示:'GROUP BY') – Mchl

+0

從即將到來的生日我假設你的意思是生日?使用他們的出生日期查找n個即將到來的生日嗎? –

回答

0

下面的查詢...

1)第一排序不同出生日期的(默認情況下,今天第一次排序)。

2)所述第一DOB的使用LIMIT功能,和

3)最後,選擇所有具有最早5名DOB的用戶進行選擇。

SELECT u1.* 
from USERS u1 
INNER JOIN 
( 
    SELECT DISTINCT 
     EXTRACT(MONTH FROM dob) dob_month, 
     EXTRACT(DAY FROM dob) dob_day 
    FROM users 
    ORDER BY 
    CASE 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN 1 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) < EXTRACT(DAY FROM CURDATE()) THEN -1 
     ELSE SIGN(EXTRACT(MONTH FROM dob) - EXTRACT(MONTH FROM CURDATE())) 
    END DESC, 
    CASE 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN 1 
     ELSE SIGN(EXTRACT(DAY FROM dob) - EXTRACT(DAY FROM CURDATE())) 
    END DESC,  
    EXTRACT(MONTH FROM dob) ASC, 
    EXTRACT(DAY FROM dob) ASC 
    LIMIT 5 
) selected_dobs 
ON EXTRACT(MONTH FROM u1.dob) = selected_dobs.dob_month and EXTRACT(DAY FROM u1.dob) = selected_dobs.dob_day 
ORDER BY 
    CASE 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN 1 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) < EXTRACT(DAY FROM CURDATE()) THEN -1 
     ELSE SIGN(EXTRACT(MONTH FROM dob) - EXTRACT(MONTH FROM CURDATE())) 
    END DESC, 
    CASE 
     WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN 1 
     ELSE SIGN(EXTRACT(DAY FROM dob) - EXTRACT(DAY FROM CURDATE())) 
    END DESC,  
    EXTRACT(MONTH FROM dob) ASC, 
    EXTRACT(DAY FROM dob) ASC, 
    username ASC; 

SQL Fiddle demo

注意

沒有行從SELECT過濾掉,因爲它是可能的(部分或全部),未來5個生日會出現在未來的日曆(例如今天可能是12月28日,接下來的5個生日可能發生在12月29日,12月31日,1月2日,1月5日,1月6日)。

如果您希望在列表底部選擇今天的生日(而不是上面的查詢所做的列表頂部),只需在ORDER BY子句中將1更改爲-1,如下所示

ORDER BY CASE WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN -1 WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) < EXTRACT(DAY FROM CURDATE()) THEN -1 ELSE SIGN(EXTRACT(MONTH FROM dob) - EXTRACT(MONTH FROM CURDATE())) END DESC, CASE WHEN EXTRACT(MONTH FROM dob) = EXTRACT(MONTH FROM CURDATE()) AND EXTRACT(DAY FROM dob) = EXTRACT(DAY FROM CURDATE()) THEN -1 ELSE SIGN(EXTRACT(DAY FROM dob) - EXTRACT(DAY FROM CURDATE())) END DESC, EXTRACT(MONTH FROM dob) ASC, EXTRACT(DAY FROM dob) ASC

+1

OP希望包含所有「重複」生日的實例,可能超過5人,所以這是行不通的。 –

+0

@ Clockwork-Muse感謝您的反饋!上面的修改後的查詢會選擇具有最早5個生日的所有用戶。 SQL Fiddle數據有一個超過1個用戶共享前5名生日的例子。 –

0

首先,你會希望有一個Calendar table(這個特殊的例子是SQL Server,但應該適應)。它是最有用的分析/維度表之一,您通常可以使用它們來獲取通常不具有SARG能力的查詢的基於索引的訪問。

對於這種情況,我們需要這樣一個最小的表:

CREATE TABLE (isoDate DATE, 
       dayOfMonth INTEGER, 
       month INTEGER) 

...和兩個指數,從[isoDatedayOfMonthmonth]和[dayOfMonthmonthisoDate](或[monthdayOfMonth,isoDate])。

現在,我們可以用它來獲得未來5個生日:

SELECT DISTINCT Next.isoDate, Next.month, Next.dayOfMonth 
FROM Users 
JOIN Calendar Start 
    ON Start.isoDate = Users.dateOfBirth 
JOIN Calendar Next 
    ON Next.isoDate >= CURDATE() 
    AND Next.month = Start.month 
    AND Next.dayOfMonth = Start.dayOfMonth 
ORDER BY Next.isoDate 
LIMIT 5 

這將讓月/日的日組合的所有未來的情況下,(如果必要的話,幷包括人多次)循環年前。請注意,這並不會讓人們在2月29日過生日(所以這些人每年都不會有生日)。

我們現在可以加入再次得到名稱:

SELECT Birthdays.isoDate AS dateOfBirth, Users.name 
FROM (SELECT DISTINCT Next.isoDate, Next.month, Next.dayOfMonth 
     FROM Users 
     JOIN Calendar Start 
     ON Start.isoDate = Users.dateOfBirth 
     JOIN Calendar Next 
     ON Next.isoDate >= CURDATE() 
      AND Next.month = Start.month 
      AND Next.dayOfMonth = Start.dayOfMonth 
     ORDER BY Next.isoDate 
     LIMIT 5) Birthdays 
JOIN Calendar Origin 
    ON Origin.month = Birthdays.month 
    AND Origin.dayOfMonth = Birthdays.dayOfMonth 
JOIN Users 
    ON Users.dateOfBirth = Origin.isoDate 
ORDER BY Birthdays.isoDate 

而你的黃金

相關問題