To display missing values [date] as range from Date Column - mysql

I have output as below
ID Date
Null 2012-10-01
1 2012-10-02
2 2012-10-03
NULL 2012-10-04
3 2012-10-05
NULL 2012-10-06
4 2012-10-07
NULL 2012-10-08
5 2012-10-10
NULL 2012-10-11
NULL 2012-10-12
6 2012-10-13
NULL 2012-10-16
As it has missing dates with value as NULL. I need to show final output as
2012-10-01 - 2012-10-01 (1 day )
2012-10-04 - 2012-10-04(1 day )
2012-10-06 - 2012-10-06(1 day )
2012-10-08 - 2012-10-08(1 day )
2012-10-11 - 2012-10-12(2 day )
2012-10-14 - 2012-10-14(1 day )

You can generate the date ranges using the following query:
select
min(date) as start,
max(date) as end,
datediff(max(date), min(date)) + 1 as numDays
from
(select #curRow := #curRow + 1 AS row_number, id, date
from Table1 join (SELECT #curRow := 0) r where ID is null) T
group by
datediff(date, '2012-10-01 00:00:00') - row_number;
The logic is based on a clever trick for grouping consecutive ranges. First, we filter and number the rows in the subquery. Then, the rows that are grouped together are found by comparing the number of days after 2012-10-01 to the row number. If any rows share this value, then they must be consecutive, otherwise there would be a "jump" between two rows and the expression datediff(date, '2012-10-01 00:00:00') - row_number would no longer match.
Sample output (DEMO):
START END NUMDAYS
October, 01 2012 00:00:00+0000 October, 01 2012 00:00:00+0000 1
October, 04 2012 00:00:00+0000 October, 04 2012 00:00:00+0000 1
October, 06 2012 00:00:00+0000 October, 06 2012 00:00:00+0000 1
October, 08 2012 00:00:00+0000 October, 08 2012 00:00:00+0000 1
October, 11 2012 00:00:00+0000 October, 12 2012 00:00:00+0000 2
October, 16 2012 00:00:00+0000 October, 16 2012 00:00:00+0000 1
From there I think it should be pretty trivial for you to get the exact output you are looking for.

Related

MySQL Get data by previous quarter

I am trying to find the last entry for the previous years quarter.
All I can access is year i.e 2021 and quarter i.e 1
Here is the data in my database:
id
name
start
end
16
April 2021
2021-04-01
2021-04-30
15
March 2021
2021-03-01
2021-03-31
14
February 2021
2021-02-01
2021-02-28
57
November 2020
2020-11-01
2020-11-30
55
October 2020
2020-10-01
2020-10-31
29
September 2020
2020-09-01
2020-09-30
27
July 2020
2020-07-01
2020-07-31
24
April 2020
2020-04-01
2020-04-30
23
March 2020
2020-03-01
2020-03-31
22
February 2020
2020-02-01
2020-02-29
21
January 2020
2020-01-01
2020-01-31
Using the MySQL quarter function I can get it to print out the quarter as an integer in another column:
SET #given_year = 2021;
SET #given_quarter = 1;
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions
id
name
start
end
Q
16
April 2021
2021-04-01
2021-04-30
2
15
March 2021
2021-03-01
2021-03-31
1
14
February 2021
2021-02-01
2021-02-28
1
57
November 2020
2020-11-01
2020-11-30
4
55
October 2020
2020-10-01
2020-10-31
4
29
September 2020
2020-09-01
2020-09-30
3
27
July 2020
2020-07-01
2020-07-31
3
24
April 2020
2020-04-01
2020-04-30
2
23
March 2020
2020-03-01
2020-03-31
1
22
February 2020
2020-02-01
2020-02-29
1
21
January 2020
2020-01-01
2020-01-31
1
I tried using WHERE and LIKE but it is returning 0 rows:
SELECT * FROM (
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions as s
) AS vs
WHERE
vs.end
LIKE
#given_year
AND
vs.Q < #given_quarter
I also need to account for the possibility that there may be no rows this year and I need to find the previous year.
For example with these two rows, if I was passed the year 2021 and quarter 1 I would need to return November of the previous year and a different quarter.
id
name
start
end
Q
14
February
2021
2021-02-01
2021-02-28
57
November
2020
2020-11-01
2020-11-30
If I understand correctly, you want all the rows from the quarter in the data before a given quarter. You can filter and use dense_rank():
select s.*
from (select s.*,
dense_rank() over (order by year(start) desc, quarter(start) desc) as seqnum
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
) s
where seqnum = 1;
The above returns all rows from the previous quarter (which is what I thought you wanted). If you want only one row:
select s.*
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
order by start desc
limit 1;

Mysql...Impossible query?

Difficult query. Not sure if this is possible.
I am trying to figure out how to format a query that needs to accomplish several things.
(1) I need to parse the DATE field that is a VARCHAR field and not a sql date field to get the month of each date.
(2) I then need to AVG all the PTS fields by NAME and Month. So with my example data below I would have a row that has John and John would have 2 in the JAN column and 3 in the the APR column and the AVG column would be an average of all the months. So the months are an average of all the entries in that month and the AVG column is an average of all the columns in the row.
Table:
Name (VARCAHR) PTS (INT) DATE (VARCHAR)
---------------------------------------------
John 3 Tue Apr 14 17:56:02 2020
Chris 2 Tue Apr 14 19:44:03 2020
John 2 Mon Jan 30 15:23:03 2020
Chris 4 Fri Feb 28 16:15:15 2020
John 3 Tue Apr 14 17:56:02 2020
Table Layout on web page:
Name Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Average
Not impossible, just convoluted. You can use STR_TO_DATE to convert your strings into DATETIME objects, from which you can then use MONTH to get the month number. Note though (as #DRapp commented) that you should be storing DATETIME values in their native form, not as VARCHAR, then you wouldn't have to deal with STR_TO_DATE. Having got the month number, you can then use conditional aggregation to get the results you want:
SELECT name,
COALESCE(AVG(CASE WHEN mth = 1 THEN PTS END), 0) AS Jan,
COALESCE(AVG(CASE WHEN mth = 2 THEN PTS END), 0) AS Feb,
COALESCE(AVG(CASE WHEN mth = 3 THEN PTS END), 0) AS Mar,
COALESCE(AVG(CASE WHEN mth = 4 THEN PTS END), 0) AS Apr,
-- repeat for May to November
COALESCE(AVG(CASE WHEN mth = 12 THEN PTS END), 0) AS `Dec`,
AVG(PTS) AS AVG
FROM (
SELECT name, PTS AS PTS, MONTH(STR_TO_DATE(DATE, '%a %b %e %H:%i:%s %Y')) AS mth
FROM data
) d
GROUP BY name
Output (for your sample data):
name Jan Feb Mar Apr Dec AVG
Chris 0 4 0 2 0 3
John 0 0 0 2.6667 0 2.6667
Demo on SQLFiddle

ORDER BY MONTH(1) after GROUP_CONCAT as names?

If I don't use GROUP_CONCAT() then there is no difficulty to the group and order the rows according to date-month-year
Following code:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
21 12 2019 1092 1 pinky
04 01 2020 1050 1 harshit
30 12 2019 21 1 robin
05 01 2020 987 2 chetan
31 12 2019 1239 2 rahul
30 11 2019 157.5 1 rahul
01 01 2020 651 1 rahul
15 12 2019 1575 1 isha
03 01 2020 598.5 1 manvi
SEE the names are not concating
But as soon as I add this line:
GROUP_CONCAT(users.firstname SEPARATOR '-')) AS names
like this:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
GROUP_CONCAT(users.firstname SEPARATOR '-') AS names,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
01 01 2020 651 1 rahul
03 01 2020 598.5 1 manvi
04 01 2020 1050 1 harshit
05 01 2020 987 2 chetan-saurabh
15 12 2019 1575 1 isha
21 12 2019 1092 1 pinky
30 11 2019 157.5 1 rahul
30 12 2019 21 1 robin
31 12 2019 1239 2 rahul-manvi
then the order changed by day-order(without proper month and year order) but the grouping is correct.
Am I doing something wrong?
Use ORDER BY MONTH(orders.date_time). The problem is that your date column is not formatted as a valid MySQL date, so it's not extracting the month correctly.

mysql list data excluding weekends

I have table with id (PK,AI), name and date, when users register I set date = CURDATE().
I have a PHP page where I have to list the names where CURDATE() >= (date + 3 days) excluding weekends (Sat and Sunday) means I list names of users who completed the registration before 3 days but I don't count weekends.
which means if someone register on Monday, he should listed on the page on Thursday and if he registered on Friday, the page list him only on Wednesday (excluded weekends)
Is there any method in MySQL to accomplish this ?
Instead of doing a complex mysql query, could you not just pass in a different date to check against, depending on the weekday from your php script?
So, instead of comparing in your sql query your date+3days <= today, pass in a variable for the date offset or just calculate the date in php and pass the date in.
day of the week | offset
1 | 5
2 | 5
3 | 5
4 | 3
5 | 3
6 | 4
7 | 5
Easy in MySQL.
SELECT CURRENT_DATE + interval (3 + 2*(weekday(CURRENt_DATE) > 1)) day;
Thanks to #JamesBlond for the table, saves me to explain. ;-)
EDIT: I was confused by the (index-killing) way to request data: normally you should try taking the date from the table unmodified and to fiddle with your CURRENT_DATE data.
As long as I understand you right, it should be the following, so you also could simply use a CASE WHEN clasue, that is more readable and easier to adopt.
thedate - interval (
3 + 2*(weekday(thedate) < 3)
+ (weekday(thedate) > 4) * (weekday(thedate)-4)) DAY
AS 3_days_before
http://www.sqlfiddle.com/#!2/49731/9/0
THEDATE WEEKDAY(THEDATE) THEDATE_FORMATTED 3_DAYS_BEFORE FORMATTED_3_DAYS_BEFORE
April, 27 2014 00:00:00+0000 6 Sunday April, 22 2014 00:00:00+0000 Tuesday
April, 28 2014 00:00:00+0000 0 Monday April, 23 2014 00:00:00+0000 Wednesday
April, 29 2014 00:00:00+0000 1 Tuesday April, 24 2014 00:00:00+0000 Thursday
April, 30 2014 00:00:00+0000 2 Wednesday April, 25 2014 00:00:00+0000 Friday
May, 01 2014 00:00:00+0000 3 Thursday April, 28 2014 00:00:00+0000 Monday
May, 02 2014 00:00:00+0000 4 Friday April, 29 2014 00:00:00+0000 Tuesday
May, 03 2014 00:00:00+0000 5 Saturday April, 29 2014 00:00:00+0000 Tuesday
May, 04 2014 00:00:00+0000 6 Sunday April, 29 2014 00:00:00+0000 Tuesday
May, 05 2014 00:00:00+0000 0 Monday April, 30 2014 00:00:00+0000 Wednesday
May, 06 2014 00:00:00+0000 1 Tuesday May, 01 2014 00:00:00+0000 Thursday
May, 07 2014 00:00:00+0000 2 Wednesday May, 02 2014 00:00:00+0000 Friday

Get data from table where date between given date and 1 week back

I have database dbadmin, table - tbl_empreimburse with fields-emp_id,rem_amount,rem_date.
I want to retrieve data which comes from given date to a week back.
I tried this query,
SELECT SUM(rem_amount),DATEADD(dd, -7, "2012-01-10")
FROM tbl_empreimburse
GROUP BY emp_id
HAVING emp_id='5' AND rem_date BETWEEN DATEADD(dd, -7, "2012-01-10") AND "2012-01-10"
It gives me error "FUNCTION dbadmin.DATEADD does not exist". Do I need to convert "2012-01-10" to date format? Any Help, Please?
Try this:
This query gives result as you have specified for employee id 5 and date period of 7 days.
SELECT emp_id, SUM(rem_amount)
FROM tbl_empreimburse
WHERE emp_id='5' AND DATEDIFF('2012-12-31', rem_date) BETWEEN 0 AND 7;
OR
Below query gives you all employee data.
SELECT emp_id, SUM(rem_amount)
FROM tbl_empreimburse
GROUP BY emp_id
HAVING DATEDIFF('2012-12-31', rem_date) BETWEEN 0 AND 7;
Check this *SQLFIDDLE reference out. :)
I am not sure why you are using group by clause here...
Sample date:
ID AMOUNT RDATE
1 3400 January, 01 2012 00:00:00+0000
2 5000 January, 10 2012 00:00:00+0000
3 3000 January, 02 2012 00:00:00+0000
5 1000 January, 05 2012 00:00:00+0000
5 2000 January, 04 2012 00:00:00+0000
2 2000 February, 10 2012 00:00:00+0000
Query:
select * from emp
where id = 5;
here is the query to get sum
select id, sum(amount)
from emp
where rdate between '2012-01-10' - interval 7 day
and '2012-01-10'
and id = 5
;
Results:
all records by employee id = 5
ID AMOUNT RDATE
5 1000 January, 05 2012 00:00:00+0000
5 2000 January, 04 2012 00:00:00+0000
sum of amount by employee id = 5
ID SUM(AMOUNT)
5 3000