Selecting results within diffrerent timesets in one sql query - mysql

How can select the last records added in 5 seconds, 5 minutes, 5 hours, 5 days, 5 weeks, 5 months, 5 years in one query?
Is it possible to be selected in one query?
sample records include
name | added_timestamp
v | last_five_minutes
k | last_hour
l | last_hour
the timestamps can be pseudo for the actual time

Although you haven't stated it, I suspect you want totals for the various time periods:
SELECT
SUM(date_added > NOW() - INTERVAL 5 SECOND) as total_in_last_5_seconds,
SUM(date_added > NOW() - INTERVAL 5 MINUTE) as total_in_last_5_minutes,
SUM(date_added > NOW() - INTERVAL 5 HOUR) as total_in_last_5_hours,
SUM(date_added > NOW() - INTERVAL 5 DAY) as total_in_last_5_days,
SUM(date_added > NOW() - INTERVAL 5 WEEK) as total_in_last_5_weeks,
SUM(date_added > NOW() - INTERVAL 5 MONTH) as total_in_last_5_months,
SUM(date_added > NOW() - INTERVAL 5 YEAR) as total_in_last_5_years
from records;
Edited: Added alternative prompted by comment
If you want the actual records, this will categorize them:
SELECT
*,
case
when date_added > NOW() - INTERVAL 5 SECOND then 'last_5_seconds'
when date_added > NOW() - INTERVAL 5 MINUTE then 'last_5_minutes'
when date_added > NOW() - INTERVAL 5 HOUR then 'last_5_hours'
when date_added > NOW() - INTERVAL 5 DAY then 'last_5_days'
when date_added > NOW() - INTERVAL 5 WEEK then 'last_5_weeks'
when date_added > NOW() - INTERVAL 5 MONTH then 'last_5_months'
when date_added > NOW() - INTERVAL 5 YEAR then 'last_5_years'
else 'ancient'
end as time_category
from records;

SELECT
*, /* now just don't be lazy but specify whatever columns you want to pull */
(Timestamp >= NOW() - INTERVAL 5 SECOND) AS AddedWithinSeconds,
(Timestamp >= NOW() - INTERVAL 5 MINUTE) AS AddedWithinMinutes,
(Timestamp >= NOW() - INTERVAL 5 HOUR) AS AddedWithinHours,
(Timestamp >= NOW() - INTERVAL 5 DAY) AS AddedWithinDays,
(Timestamp >= NOW() - INTERVAL 5 WEEK) AS AddedWithinWeeks,
(Timestamp >= NOW() - INTERVAL 5 MONTH) AS AddedWithinMonths
FROM atable
WHERE Timestamp >= NOW() - INTERVAL 5 YEAR
ORDER BY
AddedWithinSeconds DESC,
AddedWithinMinutes DESC,
AddedWithinHours DESC,
AddedWithinDays DESC,
AddedWithinWeeks DESC,
AddedWithinMonths DESC

Get the last records added in 5 years:
SELECT * FROM records WHERE date_added > NOW() - INTERVAL 5 YEAR
Then extract the records added in 5 seconds, 5 minutes, 5 hours, 5 days, 5 weeks, 5 months from the results.

Related

MySQL return value depending of date range

I don't understand why my SQL query doesn't work. I'm trying to do that :
if date is null then return 0
if date < 15 min then return 1
if date > 15 min and < 30 min then return 2
if date > 30 min and < 60 min then return 3
if date > 60 min and < 180 min then return 4
if date > 180 min then return 5
So here is my SQL query :
SELECT CASE
WHEN start_date IS NULL THEN 0
WHEN start_date < DATE_SUB(NOW(),INTERVAL 15 MINUTE) THEN 1
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE) THEN 2
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL 60 MINUTE) THEN 3
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND DATE_SUB(NOW(), INTERVAL 180 MINUTE) THEN 4
ELSE 5
END as remaining_time
FROM table
But I don't understand why when I got only the cases 0, 1 and 5. remaining_time is never in the. cases 2, 3 ,4.
Do you know why ?
Such condition will never be met, because the lower bound is greater than the higher bound:
start_date BETWEEN DATE_SUB(NOW(), INTERVAL 15 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE)
You should have the bounds the other way around:
SELECT CASE
WHEN start_date IS NULL THEN 0
WHEN start_date < DATE_SUB(NOW(),INTERVAL 15 MINUTE) THEN 1
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 30 MINUTE) AND DATE_SUB(NOW(), INTERVAL 15 MINUTE) THEN 2
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 60 MINUTE) AND DATE_SUB(NOW(), INTERVAL 30 MINUTE) THEN 3
WHEN start_date BETWEEN DATE_SUB(NOW(), INTERVAL 180 MINUTE) AND DATE_SUB(NOW(), INTERVAL 60 MINUTE) THEN 4
ELSE 5
END as remaining_time
FROM table
CASE stops on the first matching condition, so this can be simplified as follows:
SELECT CASE
WHEN start_date is NULL THEN 0
WHEN start_date < NOW() - INTERVAL 15 MINUTE THEN 1
WHEN start_date < NOW() - INTERVAL 30 MINUTE THEN 2
WHEN start_date < NOW() - INTERVAL 60 MINUTE THEN 3
WHEN start_date < NOW() - INTERVAL 180 MINUTE THEN 4
ELSE 5
END as remaining_time
FROM table

MySQL- How to query to get rows between certain years

I am trying to get back rows that are between year ranges, such as from 0-5 years, 5-10 years, 10-15 etc.
So far, I've only been able to product between 0-5 but need some help on querying between 5-10 years etc.
SELECT *
FROM users
WHERE start_date >= DATE_SUB(NOW(),INTERVAL 5 YEAR)
I've tried using the BETWEEN function, but could be using it incorrectly. Open to suggestions.
I'm not a fan of hard coding values in for the dates because I don't want to go back every few years and change it.
Assuming start_date is DATE datatype (not DATETIME or TIMESTAMP)
five years ago up to today
WHERE start_date > DATE(NOW()) + INTERVAL -5 YEAR
AND start_date <= DATE(NOW()) + INTERVAL 0 YEAR
ten years ago up to five years ago
WHERE start_date > DATE(NOW()) + INTERVAL -10 YEAR
AND start_date <= DATE(NOW()) + INTERVAL -5 YEAR
You can use BETWEEN.
SELECT *
FROM users
WHERE (start_date BETWEEN NOW() AND DATE_SUB(NOW(), INTERVAL 5 YEAR))
and then for your next interval:
SELECT *
FROM users
WHERE (start_date BETWEEN DATE_SUB(NOW(), INTERVAL 5 YEAR) AND DATE_SUB(NOW(), INTERVAL 10 YEAR))
0 - 5
SELECT * FROM users
WHERE
start_date BETWEEN (CURDATE() - INTERVAL 5 YEAR) AND CURDATE();
5 - 10
SELECT * FROM users
WHERE
start_date BETWEEN (CURDATE() - INTERVAL 10 YEAR) AND (CURDATE() - INTERVAL 5 YEAR);
10 - 15
SELECT * FROM users
WHERE
start_date BETWEEN (CURDATE() - INTERVAL 15 YEAR) AND (CURDATE() - INTERVAL 10 YEAR);

MySQL Nested WHERE - OR

I will need a little help here
Problem is - after WHERE clause I only need rows where CBI is Critical or HIGH or there is combination where CBI is Medium and Priority is 1.
Unfortunately I am still getting rows where e.g. CBI is medium and priority is 2
SELECT * FROM main_table WHERE (cbi='Critical' OR cbi='High' OR (cbi='Medium' AND priority='1'))
AND start_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW()
OR involvement_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW()
OR finnish_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW();
Your Problem are the or parts between the date selection. There must be brackets arround
SELECT * FROM main_table WHERE (cbi='Critical' OR cbi='High' OR (cbi='Medium' AND priority='1'))
AND (start_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW()
OR involvement_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW()
OR finnish_date BETWEEN (NOW() - INTERVAL 12 HOUR) AND NOW());

MySQL - Get Aggregates For Last 1 Day, 7 Days, 30 Days And Allow For Records To Be Counted In More Than 1 Group

I have a table with the following data:
I am looking to group the rows into the following:
Within the last day (everything within the last 24 hours)
Within the last 7 days (everything within the last week)
Within the last 30 days (everything within the last month)
The end result for the above rows would look something like:
I can group the records into these brackets right now with:
SELECT (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN '30 Days'
END) AS Timeframe, COUNT(*) AS Count
FROM my_table
GROUP BY (CASE WHEN created_at = CURDATE() THEN '1 Day'
WHEN created_at >= CURDATE() - INTERVAL 6 DAY THEN '7 Days'
WHEN created_at >= CURDATE() - INTERVAL 29 DAY THEN'30 Days'
END)
But this will prevent individual records from being counted more than once. For example, lines 2 and 3 in the first picture needs to be counted in all three brackets (1 day, 7 days, and 30 days) - while lines 6 through 9 only needs to be counted in the 30 days bracket.
How would you do this with MySQL?
It is easiest to do this as columns, rather than rows:
SELECT SUM(created_at = CURDATE()) as today
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table;
If you want your response in several rows, instead of just one with several columns, take #Gordon Linoff as your starting point... but perform the queries "one row at at time" (it won't be as efficient, because you visit the table 4 times instead of 1!):
-- Row for the 1 day timeframe
SELECT '1 Day' AS `Timeframe`, SUM(created_at = CURDATE()) AS `Count`
FROM my_table
UNION
-- Row for the 7 days timeframe...
SELECT '7 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 6 DAY) AS `Count`
FROM my_table
UNION
SELECT '30 Days' AS `Timeframe`, SUM(created_at >= CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table
UNION
SELECT 'Older' AS `Timeframe`, SUM(created_at < CURDATE() - INTERVAL 29 DAY) AS `Count`
FROM my_table ;
If you can use MariaDB instead of MySQL, you can use a WITH, which will allow the query to be efficient again:
WITH stats AS
(
SELECT SUM(created_at = CURDATE()) as today,
SUM(created_at >= CURDATE() - INTERVAL 6 DAY) as last_7_days,
SUM(created_at >= CURDATE() - INTERVAL 29 DAY) as last_30_days,
SUM(created_at < CURDATE() - INTERVAL 29 DAY) as older
FROM my_table
)
-- Convert to rows with negligible overhead
SELECT '1 Day' AS `Timeframe`, today FROM stats
UNION
SELECT '7 Days', last_7_days FROM stats
UNION
SELECT '30 Days', last_30_days FROM stats
UNION
SELECT 'Older', older FROM stats ;
In both cases, you'll get (as of 2017-07-25):
Timeframe | today
:-------- | ----:
1 Day | 0
7 Days | 4
30 Days | 8
Older | 0
dbfiddle here

Compare the last 24h with the same period a year ago in MySQL

I have a requirement to compare the last 24h with the same period a year ago.
If I do:
event_date < now() - INTERVAL 365 DAY and event_date > now() - INTERVAL 366 DAY
it does not take into consideration leap years.
The where clause you would need to create the condition for the records a year ago would be:
WHERE event_date >= DATE_SUB(DATE_SUB(NOW(), INTERVAL 1 YEAR), INTERVAL 24 HOUR)
AND event_date <= DATE_SUB(NOW(), INTERVAL 1 YEAR)
By doing it this way you will not have to worry about the leap years.
To get the data for the current past 24 hours you would use:
WHERE event_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND event_date <= NOW()
try
event_date < now() - INTERVAL 1 YEAR
AND event_date > now() - INTERVAL 1 YEAR - INTERVAL 1 DAY
or try
event_date BETWEEN (now() - INTERVAL 1 YEAR - INTERVAL 1 DAY)
AND (now() - INTERVAL 1 YEAR)