5

我正在尝试整理一个结果集,该结果集提供按即将到来的生日排序的 5 个最接近的用户。在闰年开始之前,这非常有效。例如:

  • 5 月 15 日 - 还剩 96 天
  • 5 月 15 日 - 还剩 97 天

最高的结果是 1987 年的出生,最低的结果是 1988 年的出生。u_birth 存储为 yyyy-mm-dd。有没有一种简单的方法可以对这个问题进行排序而不必重写整个查询?

SELECT u_birth, IF( DAYOFYEAR( u_birth ) >= DAYOFYEAR( NOW() ), 
          DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ), 
          DAYOFYEAR( u_birth ) - DAYOFYEAR( NOW() ) +  
      DAYOFYEAR( CONCAT( YEAR( NOW() ), '-12-31' ) ) 
 )  
 AS distance
FROM (blog_users)
WHERE `s_agehide` = 0
ORDER BY distance ASC
LIMIT 5

此查询取自 mysql 手册并进行了修改:http: //dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html#c7489

4

4 回答 4

8

如果您的算法取决于人的出生年份,那么显然存在问题。要解决此问题,首先找到每个人在当前日期之后的下一个生日,然后计算该日期与现在之间的差异。

SELECT u_birth, DATEDIFF(next_birthday, NOW()) AS distance FROM (
    SELECT *, ADDDATE(birthday, INTERVAL birthday < DATE(NOW()) YEAR) AS next_birthday
    FROM (
        SELECT *, ADDDATE(u_birth, INTERVAL YEAR(NOW()) - YEAR(u_birth) YEAR) AS birthday
        FROM blog_users
        WHERE s_agehide = 0
    ) AS T1
) AS T2
ORDER BY distance ASC
LIMIT 5

结果:

'1992-02-29', 20
'1993-03-01', 21
'1987-05-15', 96
'1988-05-15', 96
'1988-09-18', 222

测试数据:

CREATE TABLE blog_users (u_birth NVARCHAR(100) NOT NULL, s_agehide INT NOT NULL);
INSERT INTO blog_users (u_birth, s_agehide) VALUES
('1987-05-15', 0),
('1988-05-15', 0),
('1988-09-20', 0),
('2000-01-02', 0),
('2000-01-03', 1),
('1988-09-19', 0),
('1988-09-18', 0),
('1992-02-29', 0),
('1993-03-01', 0);

请注意,在闰日出生的人被假定在非闰年的 2 月 28 日生日。

此外,您的查询不包括用户的用户 ID。我想你可能也想添加这个。

于 2010-02-08T20:14:01.467 回答
2
SELECT
    CONCAT(
        YEAR(CURRENT_DATE()),
        '-',
        DATE_FORMAT((birthDate),
            '%m-%d'
        )
    ),
    fullName
FROM
    employees
WHERE
    birthDate != 0
AND(
    CONCAT(
        YEAR(CURRENT_DATE())+ 1,
        '-',
        DATE_FORMAT((birthDate),
            '%m-%d'
        )
    )BETWEEN CURRENT_DATE()
    AND DATE_ADD(
        CURRENT_DATE(),
        INTERVAL 21 DAY
    )
    OR CONCAT(
        YEAR(CURRENT_DATE()),
        '-',
        DATE_FORMAT((birthDate),
            '%m-%d'
        )
    )BETWEEN CURRENT_DATE()
    AND DATE_ADD(
        CURRENT_DATE(),
        INTERVAL 21 DAY
    )
)

ps:birthDate是我存储员工出生日期的列。 employees是表名。

于 2011-08-27T15:27:35.360 回答
1

也许有人会从这种和平的代码中得到启发。

在我的情况下它工作得很好,但我认为有很多日期计算......

SELECT CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )), fe_users.* 
FROM `fe_users`
WHERE `date_of_birth` != 0 AND (
     CONCAT(YEAR(CURRENT_DATE())+1,'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
     OR
     CONCAT(YEAR(CURRENT_DATE()),'-',DATE_FORMAT( FROM_UNIXTIME(date_of_birth), '%m-%d' )) BETWEEN CURRENT_DATE() AND DATE_ADD(CURRENT_DATE(), INTERVAL 7 DAY)
)

通过这种 SQL 代码的和平,您将获得表 fe_users 的所有用户,其 date_of_birth(保存为 unix-timestamp)将在接下来的 7 天内。您可以通过更改 date_add() 函数使用的时间间隔轻松地将其延长至 21 天。

于 2011-02-09T01:15:37.407 回答
1

闰年 2 月 29 日之后不要使用dayofyear任何东西,因为闰年​​比平时多一天。相反,提取月份和日期并将它们与今天的年份连接在一起。然后进行比较。

像这样:

SELECT u_birth, 
  IF(DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) >= DATE(NOW()),
...

预计到达时间:

就这样我不必重写将出生日期转换为生日的表达式,我会将其粘贴在一个变量中。我建议您编写一个进行转换的函数,以便您可以直接在查询中使用它。

SET @birthday= SELECT DATE(CONCAT(YEAR(NOW()),'-',MONTH(u_birth),'-',DAY(u-birth))) FROM users WHERE user_id=x; //obviously only good for one value, but use the example for the calculation

SELECT u_birth, 
       IF(DATE(@birthday)>=DATE(NOW()), 
          DATEDIFF(DATE_ADD(@birthday, INTERVAL 1 YEAR),NOW()), 
          DATEDIFF(NOW(),@birthday)
       ) as days
FROM users WHERE user_id=x;
于 2010-02-08T20:02:41.730 回答