Mysql select value depending in condition - mysql

Date | ID | Value
10-01 01 100
10-01 02 200
10-01 03 300
10-02 01 1000
10-02 02 2000
10-02 03 3000
My table has a daily entry for every id, with a different value per entry.
I need the query to show:
ID Date1Value Date2Value
01 100 1000
02 200 2000
03 300 3000
Date 1 will be DATE_SUB(curdate(), Interval 1 DAY), while Date2 is DATE_SUB(curdate(), Interval 2 DAY)

You can use conditional aggregation for this:
select id,
max(case when date = date_sub(curdate(), Interval 1 DAY)
then value
end) date1value,
max(case when date = date_sub(curdate(), Interval 2 DAY)
then value
end) date2value
from yourtable
group by id

Related

how may i select the time interval from last month ?, and it must also be between 1pm from last day of the last month till midday of the actual day

I've been trying to solve this problem for a few hours , so far what i have reached is something like this:
SELECT * FROM mytable WHERE DATE(datetime_column)
BETWEEN DATE_SUB(DATE_FORMAT(NOW(),'%Y-%M-01'),INTERVAL 1 DAY) AND NOW()
AND HOUR(datetime_column) > = '13'
ORDER BY
datetime_column
Besides the day interval, i also need the hour interval which must be between 13h pm from last day of the last month till midday for present date.
The fiddle doesnt seem to work with the current query but its working in my database, but check fiddle for more info:
https://www.db-fiddle.com/f/a3jui7aPMevU81Cka4BqXg/0
And sample data:
CREATE TABLE mytable (
id INT,
datetime_column DATETIME
);
INSERT INTO mytable (id,datetime_column) VALUES
(1,'2020-03-31 08:00:00'),
(2,'2020-03-31 13:00:00'),
(3,'2020-04-02 14:30:00'),
(4,'2020-04-06 18:00:00'),
(5,'2020-04-21 05:00:00'),
(6,'2020-04-23 13:00:00'),
(7,'2020-04-23 14:00:00');
If more info is necessary please let me know.
I think this what you want
SELECT * FROM mytable
WHERE (
DATE(datetime_column) > LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
AND datetime_column < (CURDATE() + INTERVAL 12 HOUR)
)
OR (
DATE(datetime_column) = LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
AND HOUR(datetime_column) >= 13
);
+------+---------------------+
| id | datetime_column |
+------+---------------------+
| 2 | 2020-03-31 13:00:00 |
| 3 | 2020-04-02 14:30:00 |
| 4 | 2020-04-06 18:00:00 |
| 5 | 2020-04-21 05:00:00 |
+------+---------------------+
2 rows in set (0.00 sec)
Here LAST_DAY(CURDATE() - INTERVAL 1 MONTH) gives the last day of previous month.
And datetime_column < (CURDATE() + INTERVAL 12 HOUR) tests if that time is before mid day of today.

SQL select all data that past 45 days

I have "alerts" table with date field - targetDate.
I would like to select all data that past 45 days.
I tried the code below but it's not return any results...
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon'
AND DATEDIFF( CURDATE( ) , targetDate ) > 45
Table
id userID type refID createDate targetDate lastSendDate sent valid
1 26 travelSoon NO 2018-05-02 13:54:25 0000-00-00 2018-05-02 00:00:00 0 1
2 26 travelSoon NO 2018-05-02 13:55:50 2018-06-01 0000-00-00 00:00:00 0 1
3 26 travelSoon DK 2018-05-02 13:56:12 2018-12-01 0000-00-00 00:00:00 0 1
4 26 travelSoon 2018-05-02 13:59:50 0000-00-00 0000-00-00 00:00:00 0 1
5 26 travelSoon 2018-05-02 14:00:09 2018-08-01 0000-00-00 00:00:00 0 1
6 26 travelSoon DK 2018-05-02 14:00:48 2018-08-01 0000-00-00 00:00:00 0 1
7 26 travelSoon 2018-05-02 16:45:18 2018-05-01 0000-00-00 00:00:00 0 1
8 26 travelSoon RO 2018-05-02 16:45:45 2018-04-01 0000-00-00 00:00:00 0 1
Using DATEDIFF() is a bad idea. It blocks the ability to use indexes, and there is an alternative that doesn't...
SELECT *
FROM alerts
WHERE type = 'travelSoon'
AND targetDate >= DATEADD(DAY, -45, GETDATE()) -- SQL Server
AND targetDate >= CURDATE() - INTERVAL 45 DAY -- MySQL
http://www.sqlfiddle.com/#!9/4ecdc0/6
In MSSQL DATEDIFF(interval, date1, date2) returns interval of date2 - date1.
Interval should be selected from this list:
- year, yyyy, yy = Year
- quarter, qq, q = Quarter
- month, mm, m = month
- dayofyear = Day of the year
- day, dy, y = Day
- week, ww, wk = Week
- weekday, dw, w = Weekday
- hour, hh = hour
- minute, mi, n = Minute
- second, ss, s = Second
- millisecond, ms = Millisecond`
Then use:
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon'
AND DATEDIFF(day, targetDate, GETDATE() ) > 45
For MySQL you can use TIMESTAMPDIFF(unit,date1,date2) which returns interval of date1 - date2.
unit can be selected from MICROSECOND (microseconds), SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, or YEAR.
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon'
AND TIMESTAMPDIFF(DAY, CURDATE( ), targetDate) > 45
The ANSI Standard syntax would be:
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon' AND
targetDate >= CURRENT_DATE - interval '45 day' AND
targetDate <= CURRENT_DATE;
In MySQL (which your syntax suggests:
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon' AND
targetDate >= CURRENT_DATE - interval 45 day AND
targetDate <= CURRENT_DATE;
Try this...
SELECT userid, refid, `targetdate`
FROM alerts
WHERE type = 'travelSoon'
AND Datediff(Curdate(), targetDate) < 45 -- or <=45
AND Datediff(Curdate(), targetDate) > 0
Online Demo: http://www.sqlfiddle.com/#!9/4ecdc0/4/0
If you only use Datediff(Curdate(), targetDate) < 45 condition, it may return both past and future dates. Please refer the below table.
Today: May 10, 2018
+----+-------------+
| id | targetDate | DATEDIFF(CURDATE(), targetDate)
+----+-------------+
| 2 | 𝟮𝟬𝟭𝟴-𝟬𝟲-𝟬𝟭 | -22
| 3 | 𝟮𝟬𝟭𝟴-𝟭𝟮-𝟬𝟭 | -205
| 5 | 𝟮𝟬𝟭𝟴-𝟬𝟴-𝟬𝟭 | -83
| 6 | 𝟮𝟬𝟭𝟴-𝟬𝟴-𝟬𝟭 | -83
| 7 | 2018-05-01 | 9
| 8 | 2018-04-01 | 39
+----+-------------+
To avoid this, you can use another condition like this...
Datediff(Curdate(), targetDate) > 0
SELECT userID, refID, `targetDate`
FROM alerts
WHERE type = 'travelSoon'
AND targetDate >= ( CURDATE() - INTERVAL 45 DAY )

Count all records in last 12 hours on hourly basis in mysql

I want to count records hourly in last 12 hours from my mysql table.
I found this link but my problem is, let say currently it's January 7 2016, 9 AM then i would like to count records from 7th Jan 9AM to Jan 6th 9PM.
My table structure is as following:
Table name :: cebod_cdr
id|userid|starting_date|total_duration
1 | 17 | 2016-01-07 09:00:00 | 12
2 | 17 | 2016-01-07 07:30:24 | 45
3 | 17 | 2016-01-07 01:12:21 | 5
4 | 17 | 2016-01-06 10:30:00 | 18
5 | 17 | 2016-01-06 10:45:00 | 25
Example output
hour | calls
9AM | 1
8AM | 0
7AM | 1
6AM | 0
5AM | 0
4AM | 0
3AM | 0
2AM | 0
1AM | 1
12AM | 0
11PM | 0
10PM | 2
If there is any problem in displaying hours in desired format(1-12), i can display it in some other format like 24 hours format etc.
SELECT HOUR(starting_date) AS Hour, COUNT(*) AS calls
FROM cebod_cdr
WHERE starting_date > DATE_ADD(NOW(), INTERVAL -12 HOUR)
GROUP BY HOUR(starting_date)
I have found the answer as below:
SELECT za_hours.za_hour as hour, COUNT(id) as calls
FROM (
SELECT NOW() - INTERVAL 1 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 2 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 3 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 4 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 5 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 6 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 7 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 8 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 9 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 10 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 11 HOUR as za_hour UNION
SELECT NOW() - INTERVAL 12 HOUR as za_hour )
za_hours
LEFT JOIN
cebod_cdr
ON DATE_FORMAT(za_hours.za_hour, '%Y-%m-%d %H:') = DATE_FORMAT(starting_date, '%Y-%m-%d %H:')
AND starting_date >= NOW() - INTERVAL 12 HOUR
GROUP BY za_hours.za_hour
ORDER BY za_hours.za_hour
Please suggest if i can improve this query.
Try this:
SELECT
date_format(dh.starting_date, '%Y-%m-%d %H:%i:%s') as hour,
COUNT(md.id) AS count
FROM
cebod_cdr dh
LEFT JOIN cebod_cdr md ON dh.starting_date = DATE_FORMAT(md.starting_date, '%Y-%m-%d %H:00:00')
WHERE dh.starting_date >= DATE_SUB(NOW(),INTERVAL 12 HOUR)
AND dh.starting_date < NOW()
GROUP BY dh.starting_date
ORDER BY dh.starting_date

mysql group by month with custom starting day

Is there a way in mysql to group by month, but with custom starting dates.
Say I want to count logins in a monthly basis, but with the condition that the month starts when a user register.
So for example user A registered on January 30th and user B on January 15th
I should group the logins as follow:
* User A: January 30th - February 28th, March 1st - March 30th, March 31 - April 30 and so on and so forth
* User B: January 15th - February 14th, February 15th - March 14th and so on and so forth
I guess I need to use something like DATE_ADD('2013-01-30', INTERVAL 1 MONTH); but I can not seem to find a way to make the grouping.
UPDATE
#GarethD: You are right that was a typo
In general the month should start at the same day of the next month or the last day of the next month in case that the first is not possible, so if you registered in day 31, the month period would start in day 30 for months that does not have 31 days and the last day of February either 28 or 29
Example:
Given that
id 1 registered on 2012-12-16
id 2 registered on 2013-01-29
and the following table
+----+------------+
| id | date |
+----+------------+
| 1 | 2013-01-15 |
| 1 | 2013-01-16 |
| 1 | 2013-01-17 |
| 1 | 2013-01-17 |
| 2 | 2013-03-20 |
| 2 | 2013-03-21 |
| 2 | 2013-03-28 |
| 2 | 2013-03-29 |
| 2 | 2013-03-30 |
+----+------------+
the results should be
+----+----------------------------+-------+
| id | range | count |
+----+----------------------------+-------+
| 1 | 2012-12-16, 2013-01-15 | 1 |
| 1 | 2013-01-16, 2013-02-15 | 3 |
| 2 | 2013-02-2[8|9], 2013-03-28 | 3 |
| 2 | 2013-03-29, 2013-04-28 | 2 |
+----+----------------------------+-------+
I hope the intent is clearer now.
For the following I am assuming you already have a numbers table, If you don't have a numbers table, then I'd recommend you make one then, but if you don't want to then you can create a number list on the fly
You can get a list of all boundaries by cross joining your userID and registered dates with your numbers table:
SELECT u.ID,
DATE_ADD(RegisteredDate, INTERVAL n.Number MONTH) PeriodStart,
DATE_ADD(RegisteredDate, INTERVAL n.Number + 1 MONTH) PeriodEnd
FROM User u
CROSS JOIN Numbers n;
This gives a table like:
ID PERIODSTART PERIODEND
1 2012-12-16 2012-12-16
2 2013-01-29 2013-01-29
1 2013-01-16 2013-01-16
2 2013-02-28 2013-02-28
Example on SQL Fiddle
You then need to join this to your main table, and do the count:
SELECT u.ID,
u.PeriodStart,
DATE_ADD(PeriodEnd, INTERVAL -1 DAY) PeriodEnd,
COUNT(*) AS `COUNT`
FROM ( SELECT u.ID,
DATE_ADD(RegisteredDate, INTERVAL n.Number MONTH) PeriodStart,
DATE_ADD(RegisteredDate, INTERVAL n.Number + 1 MONTH) PeriodEnd
FROM User u
CROSS JOIN Numbers n
) u
INNER JOIN T
ON T.ID = u.ID
AND T.Date >= u.PeriodStart
AND T.Date < PeriodEnd
GROUP BY u.ID, u.PeriodStart, u.PeriodEnd;
Giving a final result of:
ID PERIODSTART PERIODEND COUNT
1 2012-12-16 2013-01-15 1
1 2013-01-16 2013-02-15 3
2 2013-02-28 2013-03-28 3
2 2013-03-29 2013-04-28 2
Full Example on SQL-Fiddle
You can obviously concatenate your period start and end dates to make a 'range' string, but this is probably best handled in your application layer.
EDIT
This can be achieved with no subqueries which is likely to perform better:
SELECT u.ID,
DATE_ADD(u.RegisteredDate, INTERVAL n.Number MONTH) PeriodStart,
DATE_ADD(DATE_ADD(u.RegisteredDate, INTERVAL n.Number + 1 MONTH), INTERVAL -1 DAY) PeriodEnd,
COUNT(*) AS `COUNT`
FROM User u
CROSS JOIN Numbers n
INNER JOIN T
ON T.ID = u.ID
AND T.Date >= DATE_ADD(u.RegisteredDate, INTERVAL n.Number MONTH)
AND T.Date < DATE_ADD(u.RegisteredDate, INTERVAL n.Number + 1 MONTH)
GROUP BY u.ID, u.RegisteredDate, n.Number;
Example with no subquery on SQL-Fiddle
EDIT 2
This will get you all periods for all users up until the current period (i.e. where today falls within the date range)
SELECT u.ID,
DATE_ADD(u.RegisteredDate, INTERVAL n.Number MONTH) PeriodStart,
DATE_ADD(DATE_ADD(u.RegisteredDate, INTERVAL n.Number + 1 MONTH), INTERVAL -1 DAY) PeriodEnd,
COUNT(T.ID) AS `COUNT`
FROM User u
CROSS JOIN Numbers n
LEFT JOIN T
ON T.ID = u.ID
AND T.Date >= DATE_ADD(u.RegisteredDate, INTERVAL n.Number MONTH)
AND T.Date < DATE_ADD(u.RegisteredDate, INTERVAL n.Number + 1 MONTH)
WHERE DATE_ADD(u.RegisteredDate, INTERVAL n.Number + 1 MONTH) <= CURRENT_TIMESTAMP
GROUP BY u.ID, u.RegisteredDate, n.Number;
Example on SQL Fiddle

Getting Total Daily Sale for 7 days

I am trying to get the date and SUM(total) for last 7 days. I am trying this code and getting date NULL and daily_sale 0.00
SELECT
date,
IFNULL( SUM( total ), 0 ) AS daily_sale
FROM sales
WHERE date BETWEEN NOW()
AND DATE_SUB(NOW(), INTERVAL 7 DAY)
I am note sure how to get the date and daily total sale. I want get results as
date daily_sale
2013-01-29 500.00
2013-01-28 500.00
2013-01-27 500.00
2013-01-26 500.00
...
2013-01-23 500.00
You can try with interval - 7 day:
SELECT date, SUM(Coalese(total,0)) AS daily_sale
FROM yourtable
WHERE date BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL -7 DAY)
Not sure why between didn't work, check this out:
SQLFIDDLE DEMO
select dates, sum(coalesce(daily_sale,0)) as total
from sales
where dates <= NOW()
and dates >= Date_add(Now(),interval - 7 day)
group by dates
;
| DATES | TOTAL |
------------------------------------------
| January, 23 2013 00:00:00+0000 | 500 |
| January, 24 2013 00:00:00+0000 | 500 |
| January, 27 2013 00:00:00+0000 | 1500 |
| January, 28 2013 00:00:00+0000 | 1000 |
| January, 29 2013 00:00:00+0000 | 500 |
If the first date expression needs to be the lower one, as #diEcho's answer suggests, then you need to make NOW() the second term in the expression, not the first.
You should use the lowest date first in BETWEEN command so NOW() have to be in the end
SELECT
date,
IFNULL( SUM( total ), 0 ) AS daily_sale
FROM sales
WHERE date BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) and NOW()
or if you need statistic for each day:
SELECT
DATE(`date`),
IFNULL( SUM( total ), 0 ) AS daily_sale
FROM sales
WHERE date BETWEEN DATE_SUB(NOW(), INTERVAL 7 DAY) and NOW()
group by DATE(`date`)
from MySQL BETWEEN...AND manual
expr BETWEEN min AND max
SO change it to
SELECT CURDATE( ),DATE_SUB( CURDATE() , INTERVAL 7 DAY ) AS weekEndDate,
`date` , SUM( COALESCE(`daily_sale`,0 ) ) AS weekly_sale
FROM tbl_sale
GROUP BY weekEndDate
LIMIT 0 , 30
Working DEMO
Note:
date is mysql reserve Keyword so wrap it in `
syntax of SUM is SUM(column_name) and your column name is daily_sales