开发者

MySQL queries and intervals

This is the toughest query I ever made: http://robertr.pastebin.com/X4bG4pFp

"SELECT  `user`.`id` ,  `user`.`fname` ,  `user`.`lname` , 
YEAR(  `user`.`bday` ) AS  `bday_year` ,  `user`.`class_id` , 
( SELECT  `class`.`class_name` 
  FROM  `wp_class_classes`  `class`开发者_JS百科 
  WHERE  `user`.`class_id` =  `class`.`id`) AS  `class_name` 
FROM  `wp_class_users`  `user` 
WHERE MONTH(  `bday` ) = $month AND DAY(  `bday` ) = $day 
OR  `user`.`fname` = 
( SELECT  `name`.`names` 
  FROM  `wp_class_namedays`  `name` 
  WHERE  `name`.`day` =  '$month.$day'
  AND  `user`.`fname` =  `name`.`names` )

This query grabs data from three different database tables to check if there is someone in the database, who has a party today. And in Latvia we have Name Days too. Anyway, this query works well, and does its job well, but now I want to make it a bit cooler.

I want it to show, who will be having a party next week. You've probably noticed these emails that Facebook sends to you every weekend showing who has a birthday coming up.

But I just can't understand how to get at least that interval?

I remember that PHP has some good functions with which you can find on which day starts month and so on, but maybe here are some bright heart, and willing to help me kick me a bit faster forward.


SELECT
  `user`.`id`,
  `user`.`fname`,
  `user`.`lname` ,
  YEAR(`user`.`bday`) AS  `bday_year`,
  `user`.`class_id`,
  (
    SELECT
      `class`.`class_name`
    FROM  `wp_class_classes`  `class`
    WHERE  `user`.`class_id` =  `class`.`id`
  ) AS  `class_name`,
  CASE
    WHEN MONTH(`week`.`Date`) = MONTH(`user`.`bday`) AND
         DAY(`week`.`Date`) = DAY(`user`.`bday`) THEN 1
    ELSE 2
  END AS `event_type`
FROM  `wp_class_users`  `user`
  LEFT JOIN  `wp_class_namedays`  `name` ON  `user`.`fname` =  `name`.`names`
  LEFT JOIN  (
    SELECT CURDATE() + INTERVAL (1 - DAYOFWEEK(CURDATE())) DAY AS `Date`  UNION ALL
    SELECT CURDATE() + INTERVAL (2 - DAYOFWEEK(CURDATE())) DAY  UNION ALL
    SELECT CURDATE() + INTERVAL (3 - DAYOFWEEK(CURDATE())) DAY  UNION ALL
    SELECT CURDATE() + INTERVAL (4 - DAYOFWEEK(CURDATE())) DAY  UNION ALL
    SELECT CURDATE() + INTERVAL (5 - DAYOFWEEK(CURDATE())) DAY  UNION ALL
    SELECT CURDATE() + INTERVAL (6 - DAYOFWEEK(CURDATE())) DAY  UNION ALL
    SELECT CURDATE() + INTERVAL (7 - DAYOFWEEK(CURDATE())) DAY
  ) `week`
    ON CONCAT(MONTH(`week`.`Date`), '.', DAY(`week`.`Date`)) IN (
      CONCAT(MONTH(`user`.`bday`), '.', DAY(`user`.`bday`)),
      `name`.`day`
    )
WHERE `week`.`Date` IS NOT NULL

The user table is joined with the name day table, and the result set is then compared against the dates of the current week. The final result set lists only those users whose birthdays or name days happen during the week.

If you want to know about the events of, for example, the next week, you can simply change the intervals in the week.Date definitions as 8 - DAYOFWEEK..., 9 - DAYOFWEEK... etc.

One last thing is, instead of the correlated subquery in the select list you could use INNER JOIN, like this:

SELECT
  `user`.`id`,
  `user`.`fname`,
  `user`.`lname` ,
  YEAR(`user`.`bday`) AS  `bday_year`,
  `user`.`class_id`,
  `class`.`class_name`
FROM  `wp_class_users`  `user`
  INNER JOIN  `wp_class_classes`  `class` ON  `user`.`class_id` =  `class`.`id`
  LEFT JOIN  `wp_class_namedays`  `name` ON  ...  /* the rest of the above script */

The event_type column as defined above can tell you whether the event is a birthday or not, but it doesn't let you know whether it's both the Birthday and a Name Day for that particular person.

In case you would like to have that distinction, you could change the event_type definition like this:

CASE
  WHEN MONTH(`week`.`Date`) = MONTH(`user`.`bday`) AND
       DAY(`week`.`Date`) = DAY(`user`.`bday`) THEN 1
  ELSE 0
END +
CASE CONCAT(MONTH(`week`.`Date`), '.', DAY(`week`.`Date`))
  WHEN `name`.`day` THEN 2
  ELSE 0
END AS `event_type`

Now the result of the column would be:

  • 1 – a birthday
  • 2 – a name day
  • 3 – both

Additionally, you could have 'B' instead of 1 and 'N' instead of 2 (and '' instead of 0). The results would be then 'B', or 'N', or 'BN'. Not sure whether + can be used for concatenation, though. If not, put both CASEs into CONCAT().


I'm not sure if I get your query right, but the command SYSDATE() is mentioned in the MySQL docs. You might want to try something like:

... where date = SYSDATE() + 7

(check the syntax, I come from Oracle ;) )

This will get the parties for the next 7 days.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜