2010-02-07 24 views
10

Tôi có ngày sinh nhật của tất cả người dùng được lưu trữ dưới dạng UNIXtimestamp và muốn gửi e-mail mỗi ngày cho người dùng có sinh nhật vào ngày đó.Sử dụng MySQL để xác định ngày sinh nhật của người dùng là

Tôi cần tạo truy vấn MySQL để nhận tất cả các hàng có chứa ngày sinh vào ngày hôm nay.

Có vẻ như điều này khá đơn giản, nhưng có lẽ tôi chỉ làm quá tải nó.

+0

Như một mặt lưu ý: ' sinh nhật được lưu trữ dưới dạng dấu thời gian unix': Bạn nên suy nghĩ về việc thay đổi điều này thành sử dụng DATETIME. Dấu thời gian chỉ có thể lưu trữ ngày từ 1970-01-01 đến khoảng năm 2038. Khi người dùng đầu tiên nhập ngày sinh trước năm 1970, bạn sẽ gặp lỗi. Kiểm tra với các tài liệu trên mysql! –

+0

Bạn có thể giả định tất cả người dùng của mình ở cùng một múi giờ không? –

Trả lời

18

này nên làm việc:

SELECT * 
     FROM USERS 
     WHERE 
     DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d') 
+5

Điều này không tính đến ngày 29 tháng 2, khi không có năm nhuận. Người dùng phải gửi email vào ngày 28 tháng 2. Bạn phải bao gồm feb thứ 29 (nếu không có ngày đó) vào feb thứ 28. – Pentium10

+7

Trẻ em sinh nhật 29 tháng 2 đã được sử dụng để kỷ niệm sinh nhật của họ chỉ 4 năm một lần. Họ nhận được đặc quyền không có ngày sinh nhật-spam. Hợp đồng công bằng, phải không? –

+0

Hãy coi trọng điều này, bạn có thể bỏ lỡ phần thưởng cho Nhà cung cấp không dây cho sinh nhật của bạn 3 năm liên tiếp không? – Pentium10

0
set @now=now(); 
select * from user where (month(birthday) = month(@now) and day(birthday) = day(@now)) or 
    (month(birthday) = 2 and day(birthday) = 29 and month(@now) = 2 and day(@now) = 28 and 
    month(date_add(@now, interval 1 day)) = 3); 
+0

Điều này không tính đến ngày 29 tháng 2, khi không có năm nhuận. Người dùng phải gửi email vào ngày 28 tháng 2. Bạn phải bao gồm feb thứ 29 (nếu không có ngày đó) vào feb thứ 28. – Pentium10

1

Câu trả lời dưới đây không thực sự làm việc. Nó không đưa vào tài khoản thực tế là một năm là 365,24 (ngày nhuận ngay bây giờ và sau đó) ngày dài, vì vậy so sánh thực tế chống lại ngày sinh của người dùng là phức tạp để nói rằng ít nhất. Tôi để nó vì lý do lịch sử.

Những câu trả lời khác nên làm việc nhưng nếu bạn muốn có một tối ưu hóa nhẹ, nói rằng nếu có nhiều nhiều hàng, bạn có lẽ tốt hơn thể hiện các truy vấn trực tiếp trong timestamp giây. Bạn có thể sử dụng các mối quan hệ (hơi liên quan vì tính đến múi giờ vào tài khoản):

today_starts = UNIX_TIMESTAMP(NOW()) - TIMESTAMPDIFF(SECOND, DATE(NOW()), NOW()) 
today_ends = today_starts + 86400 

và sau đó chọn bản ghi nơi dấu thời gian nằm giữa các giá trị đó.

+2

Điều này không tính đến ngày 29 tháng 2, khi không có năm nhuận. Người dùng phải gửi email vào ngày 28 tháng 2. Bạn phải bao gồm feb thứ 29 (nếu không có ngày đó) vào feb thứ 28. – Pentium10

+1

@Pentium Trên thực tế, tôi càng nghĩ về nó, thì đây là cái buggier. Tôi sẽ chỉnh sửa và để nó như một cảnh báo chống lại kiểu tối ưu hóa này. :) –

+0

điều này nhắc tôi về một câu nói mà tôi từng nghe: "Có thể mục đích của cuộc đời bạn chỉ là để cảnh báo cho người khác". Kudos cho bạn để đứng để trả lời của bạn! (btw: http://www.despair.com/mis24x30prin.html) –

1

Tôi lấy câu trả lời của Saggi Malachi và gia hạn để bao gồm sinh nhật vào ngày 29 tháng 2 đến ngày 28 tháng 2, nếu trong năm đó không có ngày như vậy.

SELECT * 
     FROM USERS 
     WHERE 
     DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d') 
UNION 
SELECT * 
     FROM USERS 
     WHERE 
     DATE_FORMAT(NOW(),'%Y')%4 != 0 AND DATE_FORMAT(NOW(),'%m-%d')='02-28' and DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = '02-29' 
+2

Điều này không kiểm tra đúng năm nhuận. Một năm nhuận xảy ra 4 năm một lần trừ khi năm chia hết cho 100 và không phải 400. 'isLeap = (năm% 4) == 0 &&! ((Năm% 100) == 0 && (năm% 400)! = 0) –

+2

về mặt kỹ thuật, đó không phải là cách bạn phát hiện năm nhuận (1900, 2100) không phải là năm nhuận. – user262976

+1

Thực ra, nếu bạn cần nghiêm túc về điều này, bạn phải tính đến, cứ 100 năm một lần, không có năm nhuận, nhưng cứ 400 người thì có ... Bạn sẽ không muốn gửi những đứa trẻ ngày sinh nhật hai thư vào ngày 28 tháng 2 và ngày 29 tháng 2 năm 2100 :-) –

7

Dưới đây là một câu trả lời mà bất động sản đưa vào tài khoản nhuận năm và sẽ luôn luôn cung cấp cho bạn những người dùng có sinh nhật là vào ngày 29 tháng 2 tại cùng thời điểm với những người trên 01 tháng 3.

SELECT * 
    FROM USERS 
    WHERE 
    DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = DATE_FORMAT(NOW(),'%m-%d') 
    OR (
      (
       DATE_FORMAT(NOW(),'%Y') % 4 <> 0 
       OR (
         DATE_FORMAT(NOW(),'%Y') % 100 = 0 
         AND DATE_FORMAT(NOW(),'%Y') % 400 <> 0 
        ) 
      ) 
      AND DATE_FORMAT(NOW(),'%m-%d') = '03-01' 
      AND DATE_FORMAT(FROM_UNIXTIME(birthDate),'%m-%d') = '02-29' 
     ) 
3

Vì đây được ngày càng nhiều là một câu hỏi mã golf, đây là cách tiếp cận của tôi vào giải quyết này bao gồm việc chăm sóc của năm nhuận:

select * 
from user 
where (date_format(from_unixtime(birthday),"%m-%d") = date_format(now(),"%m-%d")) 
    or (date_format(from_unixtime(birthday),"%m-%d") = '02-29' 
     and date_format('%m') = '02' 
     and last_day(now()) = date(now()) 
    ); 

Giải thích: Đầu tiên mệnh đề where kiểm tra nếu sinh nhật của ai đó là ngày hôm nay. Thứ hai đảm bảo chỉ chọn những người có ngày sinh vào ngày 29 tháng 2 nếu ngày hiện tại bằng ngày cuối cùng của tháng Hai.

Ví dụ:

SELECT last_day('2009-02-01'); -- gives '2009-02-28' 
SELECT last_day('2000-02-01'); -- gives '2009-02-29' 
SELECT last_day('2100-02-01'); -- gives '2100-02-28' 
+1

Đây là mục yêu thích của tôi vì nó có thể đọc được và không sử dụng quá nhiều chức năng. Tuy nhiên, tôi sẽ bị cám dỗ để kiểm tra xem ngày hiện tại là ngày cuối cùng của feb (không phụ thuộc vào hàng) trước khi kiểm tra xem người dùng có được sinh ra vào ngày 29 tháng 12 (phụ thuộc vào hàng) hay không. t đã tìm ra nó rồi. – Arth

1

Đây là đóng góp của tôi

SELECT 
    DAYOFYEAR(CURRENT_DATE)-(dayofyear(date_format(CURRENT_DATE,'%Y-03-01'))-60)= 
    DAYOFYEAR(the_birthday)-(dayofyear(date_format(the_birthday,'%Y-03-01'))-60) 
FROM 
    the_table 

Các bit '(dayofyear (date_format (current_date,' % Y-03-01 ')) - 60)' trả về 1 trên năm nhuận kể từ tháng 1 sẽ là ngày thứ năm 61 và 0 vào những năm bình thường.

Từ đây chỉ là vấn đề trừ đi ngày bổ sung đó đối với chế độ "is-it-my-birthday".

+0

Vào ngày 1 tháng 1 cho 'current_date' của năm nhuận và ngày 1 tháng 1 cho' the_birthday' của năm không nhuận bạn nhận được '0 = 1' .. – Arth

2

tôi đi qua với vấn đề này, và tôi chỉ sử dụng mã đơn giản này bằng cách sử dụng NOW();

$myquery = "SELECT username FROM $tblusers WHERE NOW() = bd"; 

Kết quả là ngày sinh nhật hôm nay như vậy sau khi tôi rằng làm việc trong việc gửi email đến người dùng của tôi vào ngày sinh nhật của họ.

Tôi lưu trữ người dùng của mình vào ngày thứ hai chỉ sử dụng NGÀY vì vậy tôi luôn có yy:mm:dd, do đó, điều này hoạt động như một nét duyên dáng, ít nhất với tôi, sử dụng phương pháp này.

1

Enjoy :)

select p.birthday, 
CASE YEAR(p.birthday)%4 + MONTH(p.birthday)-2 + dayofmonth(p.birthday)-29 WHEN 0 THEN 1 ELSE 0 END as isBirthday29Feb, 
CASE YEAR(now())%4 WHEN 0 THEN 1 ELSE 0 END as isThisYearLeap, 
IF(YEAR(p.birthday)%4 + MONTH(p.birthday)-2 + dayofmonth(p.birthday)-29=0 AND YEAR(now())%4 != 0, 
      DATE_ADD(DATE_ADD(p.birthday, INTERVAL 1 DAY), INTERVAL YEAR(NOW())-YEAR(p.birthday) YEAR) , 
      DATE_ADD(p.birthday, INTERVAL YEAR(NOW())-YEAR(p.birthday) YEAR) 
)as thisYearBirthDay 
from person p; 

này mang đến cho bạn sinh nhật của một người tính theo năm hiện hành. Sau đó, bạn có thể sử dụng nó để tính toán khác! Các cột isBirthday28FebisThisYearLeap được đưa ra chỉ để minh họa giải pháp.

0

Bạn có thể sử dụng truy vấn bên dưới nếu ngày sinh được lưu trữ trong bảng.

Hôm nay Sinh nhật:

select * from TABLENAME 
where DAY(FIELDNAME) = DAY(CURDATE()) 
    and MONTH(FIELDNAME) = MONTH(CURDATE()); 

Hôm qua Sinh nhật:

select * from TABLENAME 
where DAY(FIELDNAME) = DAY(DATE_ADD(CURDATE(), INTERVAL -1 DAY)) 
    and MONTH(FIELDNAME) = MONTH(CURDATE()); 

Ngày mai sinh nhật:

select * from TABLENAME 
where DAY(FIELDNAME) = DAY(DATE_ADD(CURDATE(), INTERVAL 1 DAY)) 
    and MONTH(FIELDNAME) = MONTH(CURDATE()); 
+0

Lưu ý rằng kiểm tra ngày hôm qua/ngày mai sẽ không thành công vào ngày đầu tiên hoặc ngày cuối cùng của tháng - nên tránh giải quyết ngày/tháng cho đến khi so sánh khoảng cách ngày thô. – DreadPirateShawn

1

này nên bao gồm các trường hợp năm nhuận, và sử dụng các cơ chế cập nhật nội bộ.

Về cơ bản nó hoạt động bằng cách thêm vào những năm giữa hai ngày để ngày tháng năm sinh và kiểm tra bình đẳng với ngày hiện tại:

WHERE dob + INTERVAL (YEAR(CURDATE()) - YEAR(dob)) YEAR = CURDATE(); 

Thử nghiệm:

SELECT '2012-02-29' 
     + INTERVAL (YEAR('2015-02-28') - YEAR('2012-02-29')) YEAR 
     = '2015-02-28'; /* 1, is birthday */ 

SELECT '2012-02-28' 
     + INTERVAL (YEAR('2015-02-28') - YEAR('2012-02-28')) YEAR 
     = '2015-02-28'; /* 1, is birthday */ 

SELECT '2012-02-28' 
     + INTERVAL (YEAR('2016-02-29') - YEAR('2012-02-28')) YEAR 
     = '2016-02-29'; /* 0, is NOT birthday */ 

SELECT '2012-02-29' 
     + INTERVAL (YEAR('2016-02-29') - YEAR('2012-02-29')) YEAR 
     = '2016-02-29'; /* 1, is birthday */ 
Các vấn đề liên quan