fetch results by date in a specific range repeated every N days - mysql

Assuming the following data:
+--------------------------+
| id | created_at |
+--------------------------+
| 1 | 2019-04-23 13:01:00 |
| 2 | 2019-04-23 13:18:00 |
| 3 | 2019-04-30 13:01:00 |
| 4 | 2019-04-30 13:06:00 |
| 5 | 2019-04-30 13:17:00 |
| 6 | 2019-04-30 13:23:00 |
| 7 | 2019-04-30 13:32:00 |
| 8 | 2019-05-04 13:19:00 |
| 9 | 2019-05-04 13:41:00 |
| 10 | 2019-05-04 13:51:00 |
+----+---------------------+
I'd like to fetch entries where created_at was in a 15 minutes window
3 days ago OR every repeated 7 days in the past from NOW()
For example, if i'm running the query at 2019-05-07 13:30:00, I would like to fetch entries #2 (within 14 days ago + 15 minutes), #5 (within 7 days ago + 15 minutes) and #8 (within 3 days ago + 15 minutes).
I can easily write the 3 days condition, but i'm struggling with the repeated 7 days condition.
My query so far :
SELECT id, created_at
FROM user_abstract
WHERE TIMESTAMPDIFF(MINUTE, created_at, NOW()) BETWEEN 3*24*60 AND 3*24*60+15
I created a fiddle with the above dataset and the query so far, where NOW() can be customized for testing: https://www.db-fiddle.com/f/xa4ZEqEcGUDa2N3MLrgvh3/0
Any help would be appreciated.

What about this?
SET #now = '2019-05-07 13:30:00';
SELECT id, created_at
FROM user_abstract
WHERE TIMESTAMPDIFF(MINUTE, created_at, NOW()) BETWEEN 3*24*60 AND 3*24*60+15
or MOD(TIMESTAMPDIFF(MINUTE, created_at, #now),7*24*60) <= 15

The conditions you are trying to apply are distinct so these conditions are must apply, I made changes in your query(6th entry lies in 2nd mentioned range)
SET #now = '2019-05-07 13:30:00';
SELECT id, created_at
FROM user_abstract
WHERE (TIMESTAMPDIFF(MINUTE, created_at, #now) BETWEEN 3*24*60 AND 3*24*60+15) OR
MOD(TIMESTAMPDIFF(MINUTE, created_at, #now),7*24*60) <= 15
Working demo.

Related

mysql return all rows whether data exists or not

Here is a part of table from which I am retrieving data for the last 3 months including current month
+-------------+-----------------------+
| Wo_id | updated_at |
+-------------+-----------------------+
| 1 | 2018-12-05 10:38:06 |
| 2 | 2018-12-02 15:21:17 |
| 3 | 2018-12-01 22:18:53 |
| 4 | 2018-10-25 10:38:06 |
| 5 | 2018-10-18 15:21:17 |
| 6 | 2018-10-16 22:18:53 |
| 7 | 2018-10-19 10:26:19 |
| 8 | 2018-10-27 07:06:52 |
| 9 | 2018-09-25 11:35:09 |
| 10 | 2018-09-18 12:54:27 |
The query I tried is
SELECT MONTHNAME(updated_at) month,YEAR(updated_at) year_name,
MONTH(updated_at) month_no, COUNT(*) work_orders
FROM work_orders where updated_at >= last_day(now()) + interval 1 day - interval 3 month
GROUP by MONTH(updated_at),YEAR(updated_at)
ORDER BY MONTH(updated_at) DESC
The Output I am getting is
+-------------+-------------+----------+-------------+
| month | year_name | month_no | work_orders |
+-------------+-------------+----------+-------------+
| December | 2018 | 12 | 3 |
| October | 2018 | 10 | 5 |
| September | 2018 | 9 | 2 |
As you can see the query is neglecting November as its data is not in the table. It is Including September in order to complete the cycle of 3 months which is wrong. I want the output like this
+-------------+-------------+----------+-------------+
| month | year_name | month_no | work_orders |
+-------------+-------------+----------+-------------+
| December | 2018 | 12 | 3 |
| November | 2018 | 9 | 0 |
| October | 2018 | 10 | 5 |
Can someone guide me in modifying the above mentioned query. Thanks
You need to create a table of the last three months and then LEFT JOIN that to your work orders table (using the month of the work order) to get the results you want. The table of the last 3 months can be generated using a UNION:
SELECT NOW() AS month
UNION
SELECT NOW() - INTERVAL 1 MONTH
UNION
SELECT NOW() - INTERVAL 2 MONTH
Output (as of 2018-12-07):
month
2018-12-07 11:06:15
2018-11-07 11:06:15
2018-10-07 11:06:15
Note that it is OK to subtract 1 month from the date as if the day number is larger than the number of days in the previous month it will be adjusted downward to make the date valid (see the manual).
The final query then becomes:
SELECT MONTHNAME(m.month) AS month_name, YEAR(m.month) AS year_name,
MONTH(m.month) AS month_no, COUNT(wo.Wo_id) work_orders
FROM (SELECT NOW() AS month
UNION
SELECT NOW() - INTERVAL 1 MONTH
UNION
SELECT NOW() - INTERVAL 2 MONTH) m
LEFT JOIN work_orders wo ON MONTH(wo.updated_at) = MONTH(m.month) AND
YEAR(wo.updated_at) = YEAR(m.month)
GROUP by m.month, year_name
ORDER BY m.month DESC
Note that we don't need a WHERE clause as the values in the month table restrict the data to the last 3 months that we are interested in. Also we use a LEFT JOIN so that we get a result for each month even if there were no work orders that month.
Output:
month_name year_name month_no work_orders
December 2018 12 3
November 2018 11 0
October 2018 10 5
Demo on dbfiddle

how to retrieve date from db without seconds

+---------+---------------------+
| user_id | registration_date |
+---------+---------------------+
| 6988 | 2017-07-24 12:10:29 |
| 6985 | 2017-07-23 12:10:00 |
| 6980 | 2017-07-22 11:10:40 |
| 6979 | 2017-07-21 02:30:00 |
| 6978 | 2017-07-20 08:10:15 |
| 6977 | 2017-07-19 12:10:29 |
| 6976 | 2017-07-18 12:10:00 |
| 6975 | 2017-07-17 05:10:02 |
| 6974 | 2017-07-16 06:10:11 |
| 6951 | 2017-07-15 09:10:50 |
+---------+---------------------+
select registration_date from users WHERE registration_date BETWEEN '2017-07-24 12:10' - INTERVAL 10 DAY AND '2017-07-24 12:10';
I am having this data in my sql table and i am trying to get the data between 2017-07-24 12:10 and INTERVAL 10 DAY AND '2017-07-24 12:10'(excluding seconds).
Now i want to get this | 6988 | 2017-07-24 12:10:29 | ...Means i want to ignore the seconds value from the data that is stored in the db and then get the data.so that the desired data with user_id 6988 will come.
select registration_date from users WHERE registration_date BETWEEN '2017-07-24 12:10' - INTERVAL 10 DAY AND '2017-07-24 12:10';
I am trying this...But not working .
Add the min and max value for seconds. In start add the 00 and for the range end 59 as seconds
select registration_date from users
WHERE registration_date BETWEEN '2017-07-24 12:10:00' - INTERVAL 10 DAY
AND '2017-07-24 12:10:59';
For MySQL, you can use DATE and STR_TO_DATE functions to extract/compare dates, e.g.:
SELECT DATE_FORMAT(registration_date, '%Y-%m-%d %H:%i')
FROM users
WHERE registration_date BETWEEN DATE_ADD(STR_TO_DATE('2017-07-24 12:10', '%Y-%m-%d %H:%i') - INTERVAL 10 DAY)
AND STR_TO_DATE('2017-07-24 12:10', '%Y-%m-%d %H:%i');
Here's the documentation.
You can use DATE_FORMAT to get the parts of the date that you want, and compare this.
Since you want a range of dates, you need to test that separately from the time.
WHERE DATE(registration_date) BETWEEN '2017-07-14' AND '2017-07-24'
AND DATE_FORMAT(registration_date, '%H:%i') = '12:10'

UPDATE + SET + WHERE - Dynamic minimum value

This is a follow-up to:
Dynamic minimum value for specfic range (mysql)
I do have the query to fetch the third column (lowest of the last 3 days) "Low_3_days" via SELECT command:
-----------------------------------------
| Date | Unit_ | Lowest_in_last_|
| | price | 3_days |
|----------------------------------------
| 2015-01-01 | 15 | 15 |
| 2015-01-02 | 17 | 15 |
| 2015-01-03 | 21 | 15 |
| 2015-01-04 | 18 | 17 |
| 2015-01-05 | 12 | 12 |
| 2015-01-06 | 14 | 12 |
| 2015-01-07 | 16 | 12 |
|----------------------------------------
select S.Date,Unit_price,
(select S.Date, Unit_price,
(SELECT min(s2.Unit_Price)
FROM table s2
WHERE s2.DATE BETWEEN s.DATE - interval 3 day and
s.DATE - interval 1 day
) as min_price_3_days
FROM table S;
My new challenge is - what is the best way to use UPDATE-SET-WHERE so I could add the ("Lowest_in_last_3_days") values to a new column in a table (instead of having temporary results displayed to me via SELECT).
By following the UPDATE-SET-WHERE syntax, the query would be:
UPDATE table
SET min_price_3_days =
(select S.Date, Unit_price,
(SELECT min(s2.Unit_Price)
FROM table s2
WHERE s2.DATE BETWEEN s.DATE - interval 3 day and
s.DATE - interval 1 day
) as min_price_3_days
but I have difficulties constructing the correct query.
What would be the correct approach to this? I do recognize this one is a tough one to solve.
Your UPDATE should look like:
update table set low_3_days=
(SELECT min(Unit_Price)
FROM (select unit_price, date as date2 from table) as s2
WHERE s2.date2 BETWEEN date - interval 3 day and date - interval 1 day
);
You can check it in SQLFiddle
In Fiddle I used different names for table and column. I prefer not to use SQL keywords as names

sql query with current day comparison

I have a mysql table with a due_date field which is simply an integer value.
dealID | due_day
1 | 15
2 | 25
3 | 10
4 | 9
5 | 31
6 | 20
I would like to query this table to only display the data that would be 14 days before the due_day. For example, today is 01/05/13, if I query this table it should only show me dealID 1, 3 and 9. How should I go about this condition?
You can do that simply using DATE_SUB to substract the number of days from current date and then DAYOFMONTH to get the day.
You can create the query using the mentioned functions.
So based on user1951544's answer this is what I came up with.
SELECT due_day
FROM deals
WHERE (due_day - DAYOFMONTH( NOW( ) ) ) <=14
Query:
SQLFIDDLEExample
SELECT
dealID,
due_day
FROM Table1
WHERE due_day < 14 + DAYOFMONTH( NOW( ) )
Result:
| DEALID | DUE_DAY |
--------------------
| 1 | 15 |
| 3 | 10 |
| 4 | 9 |

Counting messages per day (after 17:00 counts for next day)

I have two MySQL tables: stats (left) and messages (right)
+------------+---------+ +---------+------------+-----------+----------+
| _date | msgcount| | msg_id | _date | time | message |
+------------+---------+ +----------------------+-----------+----------+
| 2011-01-22 | 2 | | 1 | 2011-01-22 | 06:23:11 | foo bar |
| 2011-01-23 | 4 | | 2 | 2011-01-22 | 15:17:03 | baz |
| 2011-01-24 | 0 | | 3 | 2011-01-22 | 17:05:45 | foobar |
| 2011-01-25 | 1 | | 4 | 2011-01-22 | 23:58:13 | barbaz |
+------------+---------+ | 5 | 2011-01-23 | 00:06:32 | foo foo |
| 6 | 2011-01-23 | 13:45:00 | bar foo |
| 7 | 2011-01-25 | 02:22:34 | baz baz |
+---------+------------+-----------+----------+
I filled in stats.msgcount, but in reality it is still empty. I'm looking for a query way to:
count the number of messages for every stats._date (notice the zero msgcount on 2011-01-25)
messages.time is in 24-hour format. All messages AFTER 5 o'clock (17:00:00) should be counted for the next day (notice msg_id 3 and 4 count for 2011-01-23)
update stats.msgcount to hold all counts
I'm especially concerned about the "later than 17:00:00 count for next day" part. Is this possible in (My)SQL?
You could use:
UPDATE stats LEFT JOIN
( SELECT date(addtime(_date,time) + interval 7 hour) as corrected_date,
count(*) as message_count
FROM messages
GROUP BY corrected_date ) mc
ON stats._date = mc.corrected_date
SET stats.msgcount = COALESCE( mc.message_count, 0 )
However this query requires dates you are interested in to be in the stats table already, if you don't have them make _date primary or unique key if its not yet and use:
INSERT IGNORE INTO stats(_date,msgcount)
SELECT date(addtime(_date,time) + interval 7 hour) as corrected_date,
count(*) as message_count
FROM messages
GROUP BY corrected_date
Really, all you're doing is shifting the times by 7 hours. Something like this should work:
UPDATE stats s
SET count = (SELECT COUNT(msg_id) FROM messages m
WHERE m._date BETWEEN DATE_SUB(DATE_ADD(s._date, INTERVAL TIME_TO_SEC(m.time) SECOND), INTERVAL 7 HOUR)
AND DATE_ADD(DATE_ADD(s._date, INTERVAL TIME_TO_SEC(m.time) SECOND), INTERVAL 17 HOUR));
The basic idea is that it takes each date in your stats table, adjusts it by 7 hours, and looks for messages sent in that range. If you used a DATETIME column instead of separate DATE and TIME columns, you wouldn't need the extra DATE_ADD(..., TIME_TO_SEC) stuff.
There may be a better way to add a date and a time, I didn't see one with a quick look at the MySQL reference documents.
So all you'd need to do is insert a new row in the stats table with a 0 for the msgcount, and run the update command. If you only wanted to update a few days (since the message count probably isn't changing 6 days later) you just need a simple where clause on the update:
UPDATE stats s
SET ...
WHERE s._date BETWEEN '2012-04-03' AND '2012-04-08'