我有一张包含姓名和出生日期的表格
我想得到与下一个即将到来的生日相对应的名字。 (其中n是整数)
使用LIMIT(我不想限制行数)是不可能的,因为它不是在限定的时间内使用BETWEEN或WHERE子句。
谢谢你的帮助
答案 0 :(得分:0)
以下查询...
1)首先对不同的dob进行排序(默认情况下,今天先排序)。
2)使用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;
注意强>
没有任何行从SELECT过滤掉,因为下一个5个生日(部分或全部)可能会在下一个日历年出现(例如今天可能是12月28日,接下来的5个生日可能会在12月发生2月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 :(得分:0)
首先,您将需要Calendar table(此特定示例适用于SQL Server,但应具有适应性)。它是最有用的分析/维度表之一,您可以经常使用它们来获取通常不具备SARG能力的查询的基于索引的访问权限。
对于这种情况,我们需要一个像这样的最小表:
CREATE TABLE (isoDate DATE,
dayOfMonth INTEGER,
month INTEGER)
...和两个索引,从[isoDate
,dayOfMonth
,month
]和[dayOfMonth
,month
,isoDate
开始](或[month
,dayOfMonth
,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
你是金色的