mysql query from hourly to 2 hourly - mysql

How can I change the query below to get 2 hours instead of 1
SELECT DATE_FORMAT(x.time,'%Y-%m-%d %H:00:00')
, avg(Ph) avg_Ph
FROM Ph x where time >= NOW() - INTERVAL 1 DAY
GROUP
BY DATE_FORMAT(x.time,'%Y-%m-%d %H:00:00');

SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(x.time)/7200)*7200),'%Y-%m-%d %H:00:00') AS `two_hour`
, avg(Ph) avg_Ph
FROM Ph x where time >= NOW() - INTERVAL 1 DAY
GROUP
BY `two_hour`

Related

SQL comparing date

I want to compare the current date with a date from a database table.
This code:
DATE_FORMAT(dt,'%y-%m')
gives me a date like this 2020-10
and i want that this code:
DATE_ADD(CURRENT_DATE, INTERVAL - 1 month)
gets date like 2020-10 not 2020-10-12(some day)
Here is the whole sql query:
select count(*)
from app_tickets t
where t.status= 3
and DATE_FORMAT(dt,'%y-%m')=DATE_ADD(CURRENT_DATE, INTERVAL - 1 month)
Thanks for help:)
This can make use of indexes
select count(*)
from app_tickets t
where t.status = 3
and t.dt >= DATE_FORMAT(CURRENT_DATE - interval 1 month ,'%Y-%m-01')
and t.dt < DATE_FORMAT(CURRENT_DATE ,'%Y-%m-01')

Get number of entries per multiple date intervals using single query

SELECT COUNT(*) FROM `table` WHERE `datetime` > SUBDATE(NOW(), INTERVAL 1 DAY)
This will get number of entries during last day. But is it possible to get number of entries for multiple intervals without having to send variation of this query multiple times (INTERVAL 1 DAY, INTERVAL 1 WEEK, INTERVAL 1 MONTH, ...)?
You need CASE WHEN expression to accomplish that.
SELECT
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 1 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END) AS lastDay,
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 7 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END ) AS lastSevenDays,
COUNT(*) AS lastThirtyDays
FROM `table`
WHERE
DATE(`datetime`) >= CURDATE() - INTERVAL 30 DAY
How to use CASE WHEN expression
Note: If your requirement is to get result of last day, last 7 days and last 30 days then go with this query.
EDIT:
If you have an index on datetime field then the above query will fail to use that index. Please use the query given below in order to utilize the index on datetime.
SELECT
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 1 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END) AS lastDay,
COUNT(CASE WHEN DATE(`datetime`) >= CURDATE() - INTERVAL 7 DAY AND DATE(`datetime`) < CURDATE() THEN 1 END ) AS lastSevenDays,
COUNT(*) AS lastThirtyDays
FROM `table`
WHERE
`datetime` >= (NOW() - INTERVAL 30 DAY - INTERVAL HOUR(NOW()) HOUR - INTERVAL MINUTE(NOW()) MINUTE - INTERVAL SECOND(NOW()) SECOND)

SQL select subquery runs forever when passing MONTH to sub query

The purpose of this query:
contracts in the database have a start date, contract date and closing date.
When a contract goes pending, the contract date is set and the closing date is set to a around 40 days in the future. I need to run a query that gets the contracts that have a contract date in the past and closing date that has not been reached to find the number of pending contracts for that month. This query generate a report of pending contracts from the last full month and going back 12 months.
My thought is to get the last day of each month and count the number of contracts that have closing date > the last day of month and contract date <= last day of month
The following query executes in 51ms. the query returns rows for July
SELECT DATE_FORMAT(LAST_DAY(NOW() - INTERVAL 2 MONTH), '%Y-%m-%d 23:59:59') as lastDay,
count(*) as total FROM contracts
WHERE L_ClosingDate >= DATE_FORMAT(LAST_DAY(NOW() - INTERVAL 2 MONTH), '%Y-%m-%d 23:59:59')
AND L_ContractDate <= DATE_FORMAT(LAST_DAY(NOW() - INTERVAL 2 MONTH), '%Y-%m-%d 23:59:59')
Now I need to run the query to get rows grouped by month, so I altered the query to the following:
select MONTH(L_ClosingDate) as m, YEAR(L_ClosingDate) as y,
(SELECT count(*) FROM contracts WHERE L_ClosingDate >= DATE_FORMAT(LAST_DAY(CONCAT(y,'-',m,'-',LPAD(1,2,'00'))), '%Y-%m-%d 23:59:59')
AND L_ContractDate <= DATE_FORMAT(LAST_DAY(CONCAT(y,'-',m,'-',LPAD(1,2,'00'))), '%Y-%m-%d 23:59:59')
) as total
FROM contracts
WHERE L_ClosingDate > DATE_ADD(NOW(), INTERVAL -2 MONTH)
AND L_CLosingDate < DATE_ADD(NOW(), INTERVAL -1 MONTH)
GROUP BY YEAR(L_ClosingDate), MONTH(L_ClosingDate)
ORDER BY L_ClosingDate DESC
It executes forever...
I've tweaked it and found that the MONTH and YEAR 'm' and 'y' in the subquery is causing the problem. If I hardcode a date it executes as expected.
Expected output:
Month | Year | total
8 | 2015 | 74
7 | 2015 | 87
6 | 2015 | 45
I'm working on getting some sample data
Is there another way to perform the group by query?
How about this? (Assumes closing date is a datetime)
SELECT MONTH(L_ClosingDate) as m, YEAR(L_ClosingDate) as y
, count(*) as total
FROM contracts
WHERE L_ClosingDate >= LAST_DAY(CURDATE() - INTERVAL 3 MONTH) + 1 DAY
AND L_CLosingDate < LAST_DAY(CURDATE() - INTERVAL 1 MONTH) + INTERVAL 1 DAY
GROUP BY m, y
ORDER BY y DESC, m DESC
;
The easy way of solve this is create a months table, and that is easy to do because only take 1200 rows for whole century.
CREATE TABLE months (
month_id int,
beginDay date,
lastDay date
)
Then your query become much more simple. Just join and calculate between

SQL Hourly Data

The query below retrieves weather data from a MySql database, and groups this data in to an hourly format.
select hour(datetime) AS hour
, avg(Temperature) as AVGT
from Database.minute
WHERE DATETIME
BETWEEN (CURDATE() + INTERVAL (SELECT hour(NOW())) hour - INTERVAL 23 hour)
AND ((CURDATE() + INTERVAL (SELECT hour(NOW())) hour))
group by hour
order by (CURDATE() + INTERVAL (SELECT hour(NOW())) hour - INTERVAL 23 hour)
Output is as follows:
hour AVGT
19 11.730
20 11.970
21 11.970
22 11.760
23 11.660
0 11.700
1 11.830
2 12.370
3 12.770
4 12.840
5 12.840
6 12.540
7 12.500
8 12.030
9 12.100
10 12.300
11 12.060
12 11.090
13 10.920
14 10.920
15 10.820
16 10.760
17 10.690
18 10.560
The time is now 18:15. All of the above output is correct apart from the data gathered for hour '18'. Instead of getting the average value between 18:00 and 18:15, it just outputs the average at time 18:00. ie. ignoring data between 18:01 and 18:14.
How can I modify the above query to include data in the current hour (18:00 to Now)?
Thanks
Why don't you simply try
SELECT Hour(datetime) AS hour,
Avg(temperature) AS AVGT
FROM DATABASE.minute
WHERE datetime BETWEEN ( Curdate() + INTERVAL (SELECT Hour(Now())) hour -
INTERVAL 23 hour ) AND Now()
GROUP BY hour
ORDER BY ( Curdate() + INTERVAL (SELECT Hour(Now())) hour - INTERVAL 23 hour )
I agree with #Ankur's answer (your filter citerion should not filter records up to the current hour, but rather the current time), however your date/time operations are very strange:
You don't need a subquery (SELECT Hour(NOW())) to obtain HOUR(NOW());
You can express ( Curdate() + INTERVAL (SELECT Hour(NOW())) hour - INTERVAL 23 hour ) more simply:
CURDATE() + INTERVAL HOUR(NOW()) - 23 HOUR
Or, in my view, more clearly:
DATE_FORMAT(NOW() - INTERVAL 23 HOUR, '%Y-%m-%d %H:00:00')
Your ORDER BY clause is a constant and therefore achieves nothing: did you mean to order by hour?
Therefore:
SELECT HOUR(datetime) AS hour,
AVG(Temperature) AS AVGT
FROM Database.minute
WHERE datetime BETWEEN
DATE_FORMAT(NOW() - INTERVAL 23 HOUR, '%Y-%m-%d %H:00:00')
AND NOW()
GROUP BY hour
ORDER BY hour

group by day for the past 5 days

I am trying to select the sum of an integer field for the past 5 days, and I need to group it for each day.
I'm having a bit of issues figuring out the grouping. Here's my sql query so far:
select
sum(`amount_sale`) as total
from `sales`
where the_date >= unix_timestamp((CURDATE() - INTERVAL 5 DAY))
that works fine for generating the sum for all 5 days together, but I need to break this down so that it shows the sum for each of the past 5 days i.e:
day 1 - $200
day 2- $500
day 3 - $20
etc.
SELECT DATE(FROM_UNIXTIME(the_date)) AS dt, SUM(amount_sale) AS total
FROM sales
WHERE the_date >= UNIX_TIMESTAMP((CURDATE() - INTERVAL 5 DAY))
GROUP BY
dt
To returns 0 for missing dates:
SELECT dt, COALESCE(SUM(amount_sale), 0) AS total
FROM (
SELECT CURDATE() - INTERVAL 1 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 2 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 3 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 4 DAY AS dt
UNION ALL
SELECT CURDATE() - INTERVAL 5 DAY AS dt
) d
LEFT JOIN
sales
ON the_date >= UNIX_TIMESTAMP(dt)
AND the_date < UNIX_TIMESTAMP(dt + INTERVAL 1 DAY)
GROUP BY
dt
This is not a very elegant solution, however, MySQL lacks a way to generate recordsets from scratch.
use the format function to return weekday nr: SELECT DATE_FORMAT(the_date, '%w');
use between
like select * from XXX where date between date(...) and date(...) group by date Limit 0,5
should do it