SQL Date Wildcards - mysql

I am using sql to write up a query in which I am trying to choose records that have their date_from column (of type date/time) that satisfy these conditions:
it can be any year
months are june, july, august and september
AND IF IT IS JUNE, IT SHOULD CONSIDER FROM THE 15th JUNE ONWARDS
Here's what i've tried ..
Select name, surname
FROM employees emp
where month(emp.date_from) IN ('06' , '07' , '08', '09')
I have also tried using CASE but failed. Any help please?

WHERE MONTH(emp.date_from) IN (7,8,9)
OR (MONTH(emp.date_from) = 6 AND DAY(emp.date_from) >= 15);
UPDATE
Or as dates are treated as strings in MySQL
WHERE RIGHT(emp.date_from, 5) BETWEEN '06-15' AND '09-30';
I don't know which would perform better however.

Sqlserver 2012
SELECT
*
FROM
employees
WHERE
DateFromParts(2000,month(date_from),day(date_from))
between '2000-06-15' and '2000-09-30'
Year 2000 is chosen because it is leap year and will handle leap year issues around 2000-02-29.

SELECT firstname,
lastname,
dateofbirth
FROM patient
WHERE Day(dateofbirth) >= CASE
WHEN Month(dateofbirth) = '06' THEN 15
END
OR Month(dateofbirth) IN ( '07', '08', '09' )
ORDER BY Month(dateofbirth)

Related

How to handle Leap Years in anniversary for a current month in MySQL

I'm attempting to write a query that finds the user's work anniversary for the current month and considers a leap year as well (don't get an idea how to manage within the query)
Table "emp_detail":
emp_no
join_date
1
2002-06-10
2
2022-06-25
3
2020-02-29
4
2002-02-15
5
2011-02-01
So far I have tried the below query:
SELECT no,
join_date
CASE WHEN DATEADD(YY,DATEDIFF(yy,join_date,GETDATE()),join_date) < GETDATE()
THEN DATEDIFF(yy,join_date,GETDATE())
ELSE DATEDIFF(yy,join_date,GETDATE()) - 1
END AS 'anniversary'
FROM emp_detail
WHERE 'status' = 'active'
HAVING MONTH(join_date) = 06/07/08 -- ...so on
EDIT:
Expected output:
For FEBRUARY month current year 2022
emp_no
join_date
anniversary_date
3
2020-02-29
2022-02-28 (Here, want get 29 Feb 2020 leap year record with non leap year 2022)
4
2002-02-15
2022-02-15
5
2011-02-01
2022-02-01
Looking for a way to display employees with anniversary dates coming up at the start of the current month considering the leap year.
Am I going in the right direction? Any help would be great.
Most (all?) SQL engines already handle year arithmetic involving leap days the way you want: folding the leap day to the final day of February.
So, computing the employee's join_date + INTERVAL x YEAR will handle '2020-02-29' correctly. To compute that interval in MySQL/MariaDB for the current year, you may use TIMESTAMPDIFF compute the difference between EXTRACTed years yourself:
SELECT emp_no,
join_date,
join_date +
INTERVAL (EXTRACT(YEAR FROM CURDATE()) -
EXTRACT(YEAR FROM join_date)) YEAR
AS "anniversary_date_this_year",
....
You can split your problem into two steps:
filtering your "join_date" values using the current month
changing the year to your "join_date"
getting the minimum value between your updated "join_date" and the last day for that date (>> this will handle leap years kinda efficiently wrt other solutions that attempt to check for specific years every time)
WITH cte AS (
SELECT emp_no,
join_date,
STR_TO_DATE(CONCAT_WS('-',
YEAR (CURRENT_DATE()),
MONTH(join_date ),
DAY (join_date )),
'%Y-%m-%d') AS join_date_now
FROM tab
WHERE MONTH(join_date) = MONTH(CURRENT_DATE())
AND YEAR(join_date) < YEAR(CURRENT_DATE())
)
SELECT emp_no,
join_date,
LEAST(join_date_now, LAST_DAY(join_date_now)) AS anniversary_date
FROM cte
Check the demo here
Note: in the demo, since you want to look at February months and we are in July, the WHERE clause will contain an additional -5 while checking the month.
You can make use of extract function in MySQL
select * from emp_detail where extract( month from (select now())) = extract( month from join_date) and extract( year from (select now())) != extract( year from join_date);
The above query will display all employees whose work anniversary is in the current month.
For the below table:
The above query will display the following rows.
The following query also considers leap year.
If the employee has joined on Feb-29 in a leap year and the current year is a non-leap year, then the query displays Anniversary Date as 'currentYear-Feb-28'
If the employee has joined on Feb-29 in a leap year and the current year is also a leap year, then the query displays Anniversay Date as 'currentYear-Feb-29'
select empId ,
case
when ( ( extract(year from (select now()))%4 = 0 and extract(year from (select now()))%100 != 0 ) or extract(year from (select now())) % 400 = 0 ) then
cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-', extract( day from join_date) ) as date)
when ( ( (extract(year from join_date) % 4 = 0 and extract(year from join_date)%100 != 0) or extract( year from join_date)%400 = 0) and extract(month from join_date) =2
and extract(day from join_date) = 29 ) then
cast( concat( cast( extract(year from (select now())) as nchar), '-02-28') as date)
else cast( concat( extract(year from (select now())), '-', extract( month from join_date),'-', extract( day from join_date) ) as date)
end as AnniversaryDate
from emp_detail
where extract(year from join_date) != extract(year from (select now()));
Emp_detail data
For this data the query will show the following rows
Further if you want to filter the date to current month only, you can make use of extract function.

MySQL ORDER BY FIELD for months

I have a table called months - this contains all 12 months of the calendar, the IDs correspond to the month number.
I will be running a query to retrieve 2 or 3 sequential months from this table, e.g
April & May
June, July, August
December & January
However I want to ensure that whenever December are January and retrieved, that it retrieves them in that order, and not January - December. Here is what I have tried:
SELECT * FROM `months`
WHERE start_date BETWEEN <date1> AND <date2>
ORDER BY
FIELD(id, 12, 1)
This works for December & January, but now when I try to retrieve January & February it does those in the wrong order, i.e "February - January" - I'm guessing because we specified 1 in the ORDER BY as the last value.
Anybody know the correct way to achieve this? As I mentioned this should also work for 3 months, so for example "November, December, January" and "December, January, February" should all be retrieved in that order.
If you want December first, but the other months in order, then:
order by (id = 12) desc, id
MySQL treats booleans as numbers, with "1" for true and "0" for false. The desc puts the 12s first.
EDIT:
To handle the more general case, you can use window functions. Assuming the numbers are consecutive, then the issue is trickier. This will work for 2 and 3-month spans:
order by (case min(id) over () > 1 then id end),
(case when id > 6 1 else 2 end),
id
I'm reluctant to think about a more general solution based only on months. After all, you can just use:
order by start_date
Or, if you have an aggregation query:
order by min(start_date)
to solve the real problem.
This is not "mysql solution" properly :
with cte (id, month) AS (
select id, month from months
union all
select id, month from months
)
, cte1 (id, month, r) as (select id, month, row_number() over() as r from cte )
select * from cte1
where id in (12, 1)
and r >= 12 order by r limit 2 ;
DECLARE
#monthfrom int = 12,
#monthto int = 1;
with months as (select 1 m
union all
select m+1 from months where m<12)
select m
from months
where m in (#monthfrom,#monthto)
order by
case when #monthfrom>#monthto
then
m%12
else
m
end
result:
12
1
Basically in MySQL this can be done the same way:
set #from =12;
set #to =1;
with recursive months(m) as (
select 1 m
union all
select m+1 from months where m<12)
select *
from months
where m in (#from,#to)
order by case when #from>#to then m%12 else m end;

Need to align as one row SQL

I have some data which I am trying to align as one row instead of two.
Example what I am getting
Name Feb Mar
Tom $229.32 NULL
Tom NULL $182.63
How I need is below
Name Feb Mar
Tom $229.32 $182.63
Below is the query which I am using
select Name,
case
when convert(varchar(7), bill_dt, 126) = '2018-02'
then sum(cast(amount as float))
end Feb,
case
when convert(varchar(7), bill_dt, 126) = '2018-03'
then sum(cast(amount as float))
end Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name, bill_dt
Use conditional aggregation:
select Name,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-02'
then cast(amount as float)
else 0
end) as Feb,
SUM( case when convert(varchar(7), bill_dt, 126) = '2018-03'
then cast(amount as float)
else 0
end) as Mar
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01'
group by Name
For your dataset, use a query that "reduces" the billing date to the first of the month (to give the report something to group by), for example:
select
Name,
DATEADD(month, DATEDIFF(month, 0, bill_dt), 0) AS bill_mnth,
amount
from psi.eop_stagging
where bill_dt >= '2018/02/01' and bill_dt < '2018/04/01';
You do not have to group yet, you can let the report do this for you. And don't use anything that sounds sophisticated and starts with "conditional", unless you want to use your report only for Febuary and March 2018.
Add a matrix to the report and use the field selector to select
Name for Rows
bill_mnth for Columns and
amount for Data
This will create a Row group grouped by Name and a Column group grouped by bill_mnth. In order to display the 3-letter abbreviation of the month instead of a date, right-click the TextBox and change the expression of that column header to
=Format(Fields!bill_mnth.Value, "MMM")
... or even "MMM yyyy" if you plan to enlarge the interval. And of course, format the data cell as desired.

Created date between that particular month mysql

I have a table event, where i have records with a field end_date, so my problem is i want to fetch number of records, grouping month wise, where end_date should with in that month only, so for example:
If a record have end_date as 2013-01-01 00:00:00 then it should be counted in January 2013, and i am not able to do that. I am unable to put that where condition, how to do tell database that end_date should be between the month for which it is currently grouping.
SELECT COUNT(*) AS 'count', MONTH(created) AS 'month', YEAR(created) AS 'year' FROM event WHERE is_approved =1 GROUP BY YEAR(created), MONTH(created)
Please help me out.
EDIT :
Data say i have is like:
Record name end_date
record_1 2013-11-01 00:00:00
record_2 2013-11-30 00:00:00
record_3 2013-12-01 00:00:00
record_4 2013-12-04 00:00:00
record_5 2013-12-06 00:00:00
record_6 2013-12-10 00:00:00
...many more
Result Expected is:
Count month year
2 11 2013
4 12 2013
....so on
Try this:
SELECT COUNT(1) AS 'count', MONTH(end_date) AS 'month', YEAR(end_date) AS 'year'
FROM event
WHERE is_approved = 1
GROUP BY EXTRACT(YEAR_MONTH FROM end_date);
OR
SELECT COUNT(1) AS 'count', MONTH(end_date) AS 'month', YEAR(end_date) AS 'year'
FROM event
WHERE is_approved = 1
GROUP BY YEAR(end_date), MONTH(end_date);
::EDIT::
1. end date is greater than that particular month - Simply add where condition in your query and pass particular month in format of YYYYMM instead of 201411
2. event is started - Add one more where condition to check whether the created date is less then current date
SELECT COUNT(1) AS 'count', MONTH(end_date) AS 'month', YEAR(end_date) AS 'year'
FROM event
WHERE is_approved = 1 AND
EXTRACT(YEAR_MONTH FROM end_date) > 201411 AND
DATE(created) <= CURRENT_DATE()
GROUP BY EXTRACT(YEAR_MONTH FROM end_date);
OR
SELECT COUNT(1) AS 'count', MONTH(end_date) AS 'month', YEAR(end_date) AS 'year'
FROM event
WHERE is_approved = 1 AND
EXTRACT(YEAR_MONTH FROM end_date) > 201411 AND
DATE(created) <= CURRENT_DATE()
GROUP BY YEAR(end_date), MONTH(end_date);
The count is aggregated based on the month and year so if you are spanning years, you wont have Jan 2013 mixed with Jan 2014, hence pulling those values too and that is the same basis of the group by.
As for your criteria, that all goes in the WHERE clause. In this case, I did anything starting with Jan 1, 2013 and ending Dec 31, 2014 via 'yyyy-mm-dd' standard date recognized format. That said, and the structure of the table you provided, I am using the "end_date" column.
SELECT
YEAR(end_date) AS EventYear,
MONTH(end_Date) AS EventMonth,
COUNT(*) AS EventCount
FROM
event
WHERE is_approved = 1
and end_date between '2013-01-01' and '2014-12-31'
GROUP BY
YEAR(end_date),
MONTH(end_Date)
Now, if you want them to have the most recent events on the top, I would put the year and month descending so 2014 is listed first, then 2013, etc and months within them as December (month 12), before the others.
GROUP BY
YEAR(end_date) DESC,
MONTH(end_Date) DESC
Your criteria could be almost anything from as simple as just a date change, approved status, or even get counts per account status is so needed, such as (and these are just EXAMPLES if you had such code status values)
SUM( is_approved = 0 ) as PendingEvent,
SUM( is_approved = 1 ) as ApprovedEvent,
SUM( is_approved = 2 ) as CancelledEvent
Per comment feedback.
For different date ranges, ignore the between clause and change the WHERE to something like
WHERE end_date > '2014-08-01' or all after a date...
where end_date < '2014-01-01' or all before a date...
They will still group by month / year. If you wanted based on a start date of the event, just change that column in instead, or do IN ADDITION to the others.
MySQL has a bunch of date and time functions that can help you with that. For example:
MONTH() Return the month from the date passed
or
YEAR() Return the year
So you can just get the month and year of your dates. And group your results by them.
SELECT
COUNT(*) cnt
,MONTH(end_date) month
,YEAR(end_date) year
FROM events
GROUP BY month, year
Result :
cnt month year
2 11 2013
4 12 2013
Update:
For filtering only the records that have an end_date greater than a particular month AND have already started, you just need to add a WHERE clause. For example, if the particular month were February 2015:
SELECT
COUNT(*) cnt
,MONTH(end_date) month
,YEAR(end_date) year
FROM events
WHERE end_date >= '2015-03-01'
AND created < NOW()
GROUP BY month, year
Alternatively, the first part of the WHERE clause can be rewritten in the following way, which is probably more comfortable to use if you have to pass the year and month as distinct parameters.
...
WHERE (YEAR(end_date) > 2015
OR (YEAR(end_date) = 2015 AND MONTH(end_date) > 02))
AND created...
SELECT COUNT(*) AS 'count', MONTH(created) AS 'month', YEAR(created) AS 'year' FROM event WHERE is_approved =1 and month(created) = "the month u want" and year(created) = "the year you want" group by GROUP BY YEAR(created), MONTH(created)
you will need to pull the month and year... i could help with that but not sure how you are getting it but months would be 01/02/03 ect and year is 2013/2014/2015 ect

Is subquery the solution to this?

Here's the table structure and some sample data:
pID.....month.....year
27 .....3 .....2008
27 .....12 .....2012
31 .....6 .....2008
99 .....1 .....2006
42 .....1 .....2009
pID is the practiceID and month and year represent the date period they've entered data for. I need to grab the number of practices that have entered data for the first time in Oct 2012, Nov 2012, Dec 2012 and so on.
I tried the following query for Oct 2012:
SELECT *
FROM
IPIPKDIS
where
practiceID NOT IN (
SELECT practiceID
from
IPIPKDIS
where
year < 2012 and month < 10
)
and year = 2012
and month = 10
and measureCatRecID = 2
ORDER BY year, month;
but it's grabbing months and year less than 10/2012.
If I run the queries isolated (not as subquery) they both work fine.
Any ideas?
This summary query will yield the first (smallest) date in the table for each value of practiceID.
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
If you want to retrieve then the whole row for the first reported month, you'd do a nested query like this:
SELECT *
FROM IPIPKDIS I
JOIN (
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
) first ON ( first.practiceID = I.practiceID
AND STR_TO_DATE( CONCAT(I.year, ' ', I.month), '%Y %m') = first.first_date)
The trick to the second query is to use the JOIN to extract just the first-month rows from your table. We use date arithmetic to do the date comparisons.