how Selecting Birthdays 7 Days Before Today in mysql - mysql

i have date field and i query for selecting Birthday before 7 days in mysql.
for example
if
birth = 1986-08-05
if now is 2012-07-30 this query alarm me.
or
birth = 1986-01-05
if now is 2012-12-30 this query alarm me.
birth is field of user_table.

select * from user_table
where date_format(date_sub(birth, interval 7 days), "%m-%d")
= date_format(now(), "%m-%d")
or date_format(date_sub(birth, interval 7 days), "%m-%d") = '02-29'
and month(now()) = 2 and month(date_add(now(), interval 1 day)) = 3

i find my select for this goal.
select *,birthdate,
concat(if(date_format(birthdate, '%m') = '12',date_format(curdate(), "%Y")
,date_format(now(), "%Y")),
date_format(date_add(curdate(), interval 7 day), '%Y')) as birthday
from users
HAVING birthday BETWEEN curdate() and date_add(curdate(), interval 7 day)
thanks from your help.

Use SQL functions if you want reusable code and want to keep your SQL easy to read and maintain. A birthday is an anniversary, so...
DROP FUNCTION IF EXISTS anniversary_after;
DELIMITER $$
CREATE FUNCTION anniversary_after(anydate DATE, after DATE)
RETURNS DATE DETERMINISTIC
BEGIN
DECLARE anniversary DATE;
DECLARE years INTEGER;
SET years = YEAR(after) - YEAR(anydate);
SET anniversary = DATE_ADD(anydate, INTERVAL years YEAR);
IF anniversary < after THEN
SET anniversary = DATE_ADD(anniversary, INTERVAL 1 YEAR);
END IF;
RETURN anniversary;
END
$$
DELIMITER ;
DROP FUNCTION IF EXISTS anniversary;
CREATE FUNCTION anniversary(anydate DATE)
RETURNS DATE DETERMINISTIC
RETURN anniversary_after(anydate, CURRENT_DATE());
Show date of next anniversary:
SELECT anniversary('1994-04-05');
Show days until next anniversary:
SELECT DATEDIFF(anniversary('1994-04-05'), CURRENT_DATE());

something like this?
SELECT user_name, DATE_SUB(birth, INTERVAL 7 DAYS) as SevenDaysBefore from user_table

Related

how to upgrade next month last day of variable in mysql stored procedure?

In my while loop procedure (IN start_date date)
DECLARE data_date date;
set data_date=start_date;
while data_date<end_date do
insert into t1
……
where date=data_date
set data_date=SELECT LAST_DAY(data_date + INTERVAL 1 MONTH);
It gets wrong because set data_date=SELECT LAST_DAY(data_date + INTERVAL 1 MONTH); but it works SELECT LAST_DAY(data_date + INTERVAL 1 MONTH) out of the procedure. How can I upgrade my data_date variable based on select last_day(……) method.
SELECT LAST_DAY(data_date + INTERVAL 1 MONTH) into data_date works.

How to find year and Month from no of days passed in sql

I have the amount of days passed , I want to find out the month and year for that particular day gap using big query SQL
For eg: I have the following fields : date_today as DATE , day_passed
as INTEGER
date_today = '2018-01-22'
day_passed = 32
From this day passed I want to create a new column like below using day_passed column value
month_joined = '2017-12'
Challenge: Months may have different days In Feb(28 or 29),30,31
What will be the best way to solve this problem?
In tsql you can use this query which I suggest you modify into a function.
declare #date nvarchar(20) = '2018-01-22'
declare #interval int = -32
declare #newDate datetime = DATEADD(DAY,#interval,CAST(#date as datetime))
select cast(year(#newDate) as nvarchar(4)) +'-'+ cast(month(#newDate) as nvarchar(2)) as 'month_joined'
To create into a function in tsql:
CREATE FUNCTION YearMonthConvert(
#Date datetime,
#Interval int = 0)
RETURNS NVARCHAR(10)
AS
BEGIN
DECLARE #newDate datetime = DATEADD(DAY,#Interval,CAST(#Date as datetime))
RETURN cast(year(#newDate) as nvarchar(4)) +'-'+ cast(month(#newDate) as nvarchar(2))
END;
then it can be called like this:
select dbo.yearmonthconvert('2018-01-22',-32)
I believe the mysql syntax is as follows - not done mysql so if anyone wants to correct me in the comments that would be much appreciated.
set #date = '2018-01-22';
set #interval = -32;
set month_joined = DATE_ADD(#date, INTERVAL #interval DAY);
Use mysql functons
DATE_SUB
or
DATE_ADD
SELECT DATE_SUB('2018-01-22', INTERVAL 32 DAY)
Result:
2017-12-21
Below is for BigQuery Standard SQL
It should give you an idea of how you can work with dates in BigQuery
#standardSQL
SELECT
date_today,
day_passed,
DATE_SUB(date_today, INTERVAL day_passed DAY) day_joined,
DATE_TRUNC(DATE_SUB(date_today, INTERVAL day_passed DAY), MONTH) month_joined_as_date,
FORMAT_DATE('%Y-%m', DATE_SUB(date_today, INTERVAL day_passed DAY)) month_joined_as_string
FROM `yourproject.yourdataset.yourtable`
you can test / play with above using dummy data from your question as below
#standardSQL
WITH `yourproject.yourdataset.yourtable` AS (
SELECT DATE '2018-01-22' date_today, 32 day_passed
)
SELECT
date_today,
day_passed,
DATE_SUB(date_today, INTERVAL day_passed DAY) day_joined,
DATE_TRUNC(DATE_SUB(date_today, INTERVAL day_passed DAY), MONTH) month_joined_as_date,
FORMAT_DATE('%Y-%m', DATE_SUB(date_today, INTERVAL day_passed DAY)) month_joined_as_string
FROM `yourproject.yourdataset.yourtable`
with result
date_today day_passed day_joined month_joined_as_date month_joined_as_string
2018-01-22 32 2017-12-21 2017-12-01 2017-12
I solved it in a simple way in bigquery
SUBSTR(STRING(DATE_ADD(DATE(date_today), -day_passed, "DAY")),1,7) AS month_joined

SQL: DATE_ADD(date,INTERVAL expr type) skip weekends

I'm currently using DATE_ADD(date,INTERVAL expr type) to set a due date as a trigger in a mySQL Database.
What I'm wanting to know is if it is possible to skip weekends (Saturday, Sunday) as part of the trigger.
You'd have to create an own function for doing that. You can look how to do that in this answer, for example (just use function instead of procedure). As for how to write such a function, here's a working algorithm. The code is quite straightforward: it loops through days and skips weekends.
CREATE FUNCTION `DAYSADDNOWK`(addDate DATE, numDays INT) RETURNS date
BEGIN
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
WHILE numDays>0 DO
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
IF (WEEKDAY(addDate)=5) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
IF (WEEKDAY(addDate)=6) THEN
SET addDate=DATE_ADD(addDate, INTERVAL 1 DAY);
END IF;
SET numDays=numDays-1;
END WHILE;
RETURN addDate;
END
Currently SELECT DAYSADDNOWK(CURDATE(), 5) yields 2016-03-07, which is correct.
Of course you only can use it with days, so no arbitrary interval, but your question mentioned date datatype, and I don't quite see how one could add a month not counting working days.
This function simply creates a list of dates starting at the date given in the arguments, and then figures out which date is x number of days (the interval) out while disregarding days 1 and 7 (which are Sunday and Saturday respectively on SQL Server).
CREATE FUNCTION [dbo].[udf_days_add_no_wknd]
(
#start_date date
, #interval int
)
RETURNS date
AS
BEGIN
declare #answer date
; with dates as
(
select #start_date as date_val
union all
select dateadd(d, 1, date_val) as date_val
from dates
where date_val < dateadd(d, #interval * 10, #start_date)
)
, final as
(
select top 1 lead(ld.date_val, #interval, NULL) over (order by ld.date_val asc) as new_date_val
from dates as ld
where 1=1
and datepart(dw, ld.date_val) not in (1,7) --eliminating weekends
)
select #answer = (select new_date_val from final)
return #answer
END
It is worth nothing that this solution is dependent on having SQL Server 2012 or later, considering the use of the lead() function.

Get the week of the month in MYSQL

I am developing a Java application using MySQL. I need to know which is the week of each month, of the stored dates. Is there any MySQL function for that ? Basically , if i was to use this for the current date (13.09) it would show me its in week number 2 and tomorrow it will be week number 3.
You can play with the WEEK() function, and see if it suits your needs. Here I'm using WEEK(date, 3) that will return the week of the year from 1 to 53, starting from Mondays:
set #my_date = '2015-09-13';
SELECT
WEEK(#my_date, 3) -
WEEK(#my_date - INTERVAL DAY(#my_date)-1 DAY, 3) + 1
AS week_number;
WEEK(date, 3) will return the week of the year of the selected date
WEEK(date - INTERVAL DAY(#my_date)-1 DAY, 3) will return the week of the year of the first day of the month of the selected date
It will return 1 for 01-March-2015 (because it's the first day of the month so it's week 1) and 2 for 02-March-2015 (because weeks starts from Mondays, so it's a new week). If this is not the desidered behaviour you should specify your requirements more precisely.
Please see a fiddle here.
Unfortunately, there isn't a "weekofmonth" function, but you could use dayofmonth, and manipulate the result a bit:
SELECT CURRENT_DATE(),
FLOOR((DAYOFMONTH(CURRENT_DATE()) - 1) / 7) + 1 AS week_of_month
Create a mysql function.
CREATE FUNCTION `WEEK_OF_MONTH`(
datee DATE
) RETURNS INT(11)
BEGIN
DECLARE DayNamee VARCHAR(20);
DECLARE StartDatee DATE;
DECLARE DayNumber INT DEFAULT 0;
SET DayNamee = (SELECT DAYNAME(datee));
SET StartDatee = (SELECT FIRST_DAY(datee));
WHILE StartDatee <= datee DO
IF DayNamee = DAYNAME(StartDatee) THEN
SET DayNumber = DayNumber + 1;
END IF;
SET StartDatee = DATE_ADD( StartDatee, INTERVAL 1 DAY);
END WHILE;
RETURN DayNumber;
END$$
DELIMITER ;
Call as --
SELECT `WEEK_OF_MONTH`('2018-12-31');
Result : 5

PostgreSQL's date_trunc in mySQL

Recently, I have been getting familiar with PostgreSQL(using 8.2) and found the date_trunc function extremely useful for easily matching time stamps between certain days/months/etc.
The real usefulness of the function, I believe, comes from the fact that it keeps the output in the format of a timestamp.
I have had to switch to mySQL(5.0) and find some of the date functions rather lacking in comparison. The extract function seems useful and the date function I have found solves some of my problems, but is there any way to replicate PostgreSQL's date_trunc?
Following is an example of how I used to use date_trunc to match queried timestamps to only the last 4 months including the current month, but only if a week has passed into this month already:
WHERE date_trunc('month', QUERY_DATE) BETWEEN
date_trunc('month', now()) - INTERVAL '4 MONTH' AND
date_trunc('month', now() - INTERVAL '1 WEEK')
I have no idea how to recreate such a stipulation in mySQL. So, my question at the end of the day, is whether this type of query can be accomplished in mySQL by trying replicate date_trunc(and how) or whether I need to start looking at these types of queries in a different way to make them work in mySQL(and suggestions on how to do that)?
The extract function seems useful and the date function I have found solves some of my problems, but is there any way to replicate PostgreSQL's date_trunc?
Indeed, EXTRACT looks like it's going to be the closest match for this specific case.
Your original code in PG:
WHERE date_trunc('month', QUERY_DATE) BETWEEN
date_trunc('month', now()) - INTERVAL '4 MONTH' AND
date_trunc('month', now() - INTERVAL '1 WEEK')
Using EXTRACT:
WHERE EXTRACT(YEAR_MONTH FROM QUERY_DATE)
BETWEEN
EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 4 MONTH)
AND
EXTRACT(YEAR_MONTH FROM NOW() - INTERVAL 1 WEEK)
While it should be functionally identical, this is actually mangling the dates into a YYYYMM string before doing the comparison.
Another option would be using DATE_FORMAT to rebuild the date string and force it to the beginning of the month:
WHERE DATE_FORMAT(QUERY_DATE, '%Y-%m-01')
BETWEEN
DATE_FORMAT(NOW() - INTERVAL 4 MONTH, '%Y-%m-01')
AND
DATE_FORMAT(NOW() - INTERVAL 1 WEEK, '%Y-%m-01')
Also, be aware that MySQL is really poor at dealing with date ranges, even when the field is indexed. You're probably going to end up with a full table scan if you aren't careful.
late to the party, but...
there is a way to get truncated date given you know the interval. For example, if the interval is MONTH, you could get today's date (now()) truncated to the month using the following:
select date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', now()) MONTH);
Given the above, one could create a function to take care of the other intervals as well:
DELIMITER //
create function date_trunc(vInterval varchar(7), vDate timestamp)
returns timestamp
begin
declare toReturn timestamp;
if vInterval = 'year' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(YEAR, '1900-01-01', vDate) YEAR);
elseif vInterval = 'quarter' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(QUARTER, '1900-01-01', vDate) QUARTER);
elseif vInterval = 'month' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MONTH, '1900-01-01', vDate) MONTH);
elseif vInterval = 'week' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(WEEK, '1900-01-01', vDate) WEEK);
elseif vInterval = 'day' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(DAY, '1900-01-01', vDate) DAY);
elseif vInterval = 'hour' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(HOUR, '1900-01-01', vDate) HOUR);
elseif vInterval = 'minute' then set toReturn = date_add('1900-01-01', interval TIMESTAMPDIFF(MINUTE, '1900-01-01', vDate) MINUTE);
END IF;
return toReturn;
end//
DELIMITER ;
Use it like so:
select date_trunc('quarter', now())
Here is a function that mimics postgres' DATE_TRUNC contract using the DATE_FORMAT mysql function that #Charles has recommended above.
DROP FUNCTION IF EXISTS DATE_TRUNC;
CREATE FUNCTION DATE_TRUNC(
in_granularity ENUM('hour', 'day', 'month', 'year'),
in_datetime datetime(6)
)
RETURNS datetime(6)
DETERMINISTIC
BEGIN
IF (in_granularity = 'hour') THEN
RETURN DATE_FORMAT(in_datetime, '%Y-%m-%d %H:00:00.0000');
END IF;
IF (in_granularity = 'day') THEN
RETURN DATE_FORMAT(in_datetime, '%Y-%m-%d 00:00:00.0000');
END IF;
IF (in_granularity = 'month') THEN
RETURN DATE_FORMAT(in_datetime, '%Y-%m-01 00:00:00.0000');
END IF;
IF (in_granularity = 'year') THEN
RETURN DATE_FORMAT(in_datetime, '%Y-01-01 00:00:00.0000');
END IF;
END;
Here are some MySQL equivalents for the most common Redshift/Postgres date_trunc expressions, using date arithmetic:
select
null
-- RS date_trunc('hour', now()) = '2023-01-13 17:00:00.000 +0100'
,date_add(date(now()), interval hour(now()) hour) as trunc_hour
-- RS date_trunc('week', now()) = '2023-01-09 00:00:00.000 +0100'
,date_sub(cast(date(now()) as datetime), interval weekday(now()) day) as trunc_week
-- RS date_trunc('month', now()) = '2023-01-01 00:00:00.000 +0100'
,date_add(cast(makedate(year(now()), 1) as datetime), interval month(now())-1 month) as trunc_month
-- RS date_trunc('year', now()) = '2023-01-01 00:00:00.000 +0100'
,cast(makedate(year(now()), 1) as datetime) as trunc_year