Why do I get
Error in query (1064): Syntax error near 'as q2)' at line 7
with
SELECT SQL_NO_CACHE q1.d1, q1.a, q2.b, (q1.a-q2.b)/q1.a*100 as Percentage
FROM
(SELECT Date(date) d1, count(id_update) a
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
GROUP BY DATE(date)) as q1
UNION ALL
(SELECT date(date) as d2, count(id_update) as b
FROM vas_updates
WHERE date BETWEEN
date_sub(date_sub(now(), interval 1 day), interval 2 hour)
AND
date_sub(now(), interval 1 day) group by DATE(d2) ) as q2
Can't I use aliases with UNION?
UPDATE:
this query might have leftovers from another query, I was tyring to understand the syntax error first.
What I'm trying to calculate is the percentage increase or decrease of two sums which are the hits from the last 2 hours of today compared to same timeframe from yesterday.
the table has just id and datetime
I suspect you actually want a JOIN
Something like this:-
SELECT SQL_NO_CACHE q1.d1, q1.a, q2.b, (q1.a-q2.b)/q1.a*100 as Percentage
FROM
(
SELECT Date(date) d1, count(id_update) a
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
GROUP BY DATE(date)
) as q1
INNER JOIN
(
SELECT date(date) as d2, count(id_update) as b
FROM vas_updates
WHERE date BETWEEN date_sub(date_sub(now(), interval 1 day), interval 2 hour) AND date_sub(now(), interval 1 day)
group by DATE(d2)
) as q2
ON q1.d1 = q2.d2
EDIT
Checked your updated query and it IS a JOIN you need.
You can use a CROSS JOIN. You are returning 1 value from each sub query, and doing a calculation on those values:-
SELECT SQL_NO_CACHE q1.d1, q1.a, q2.b, (q1.a-q2.b)/q1.a*100 as Percentage
FROM
(
SELECT MIN(Date(date)) d1, count(id_update) a
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
) as q1
CROSS JOIN
(
SELECT MIN(Date(date)) d2, count(id_update) as b
FROM vas_updates
WHERE date BETWEEN
date_sub(date_sub(now(), interval 1 day), interval 2 hour)
AND
date_sub(now(), interval 1 day)
) as q2
CROSS JOIN gives you every combination of the rows. In this case you have 1 resulting record. I have just returned the MIN date to get a single date to display.
You Can't. A UNION operation does not allow you to use alias on subqueries as it is an operation that creates a single table.
Like this:
select 1 a, 2 b
union all
select 3 blah, 4 bleh
This will result in
a b
1 2
3 4
See it here: http://sqlfiddle.com/#!2/68b32/444
On this query you only have two fields no matters what is on the second query it will only parse the first one, check if the others querys has the same quantity of fields as the first and if they are of the same type. Name the UNIONed querys with alies is invalid.
So I think what you need is probably a JOIN OR just all the fields
So, your query would be something like:
SELECT SQL_NO_CACHE tbl.d1,
tbl.a,
tbl.b,
(tbl.a-tbl.b)/tbl.a*100 as Percentage
FROM (SELECT Date(date) d1,
count(id_update) a,
null d2,
null b
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
GROUP BY DATE(date)
UNION ALL
SELECT null d1,
null a
date(date) as d2,
count(id_update) as b
FROM vas_updates
WHERE date
BETWEEN date_sub(date_sub(now(), interval 1 day), interval 2 hour)
AND date_sub(now(), interval 1 day) group by DATE(d2)
) tbl
But this most likely will not make the calculations right. You can use the version that #Kickstart has provided you.
Query of the answer from #Kickstart
SELECT SQL_NO_CACHE q1.d1, q1.a, q2.b, (q1.a-q2.b)/q1.a*100 as Percentage
FROM
(
SELECT Date(date) d1, count(id_update) a
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
GROUP BY DATE(date)
) as q1
INNER JOIN
(
SELECT date(date) as d2, count(id_update) as b
FROM vas_updates
WHERE date BETWEEN date_sub(date_sub(now(), interval 1 day), interval 2 hour) AND date_sub(now(), interval 1 day)
group by DATE(d2)
) as q2
ON q1.d1 = q2.d2
I decided to put this answer to explain why you are using the UNION operation in a wrong way.
I think that #Kickstart is right,and you can try this.
SELECT SQL_NO_CACHE d, a
FROM
(SELECT Date(date) d, count(id_update) as a
FROM vas_updates
WHERE date > date_senter code hereub(now(), interval 2 hour)
GROUP BY DATE(date))
UNION ALL
(SELECT date(date) as d, count(id_update) as a
FROM vas_updates
WHERE date BETWEEN
date_sub(date_sub(now(), interval 1 day), interval 2 hour)
AND
date_sub(now(), interval 1 day) group by DATE(d2) )
I'm wrong,UPDATE, you can try like this
SELECT SQL_NO_CACHE q1.d1, q1.a, q2.b, (q1.a-q2.b)/q1.a*100 as Percentage
FROM
(
SELECT DATE_FORMAT(Date(date),'%H') as d1, count(id_update) a
FROM vas_updates
WHERE date > date_sub(now(), interval 2 hour)
GROUP BY DATE(date)
) as q1
INNER JOIN
(
SELECT DATE_FORMAT(Date(date),'%H') as d2, count(id_update) as b
FROM vas_updates
WHERE date BETWEEN date_sub(date_sub(now(), interval 1 day), interval 2 hour) AND date_sub(now(), interval 1 day)
group by DATE(d2)
) as q2
ON q1.d1 = q2.d2
Related
I am using MySQL 5.7 and I need to do queries from a table like
order_id fee created_time
111 10 2020-11-16
222 90 2020-11-01
333 300 2000-10-22
The results should be the total income of last 1 day(yesterday) and last 30 days, like
date_range revenue
1 10
30 400
The column date_range is the last X day before now and I can do this use 'union all':
SELECT 1 AS date_range, SUM(fee) FROM test
WHERE created_time >= SUBDATE(CURRENT_DATE, 1) AND created_time < CURRENT_DATE
UNION ALL
SELECT 30 AS date_range, SUM(fee) FROM test
WHERE created_time >= SUBDATE(CURRENT_DATE, 30) AND created_time < CURRENT_DATE
The queries are quite similar and is it possible to combine them into ONE query instead of using union all?
CREATE TABLE:
CREATE TABLE test (
order_id INT,
fee INT,
created_time DATETIME
)
INSERT VALUES:
INSERT INTO test VALUES (111,10,'2020-11-16'),(222,90,'2020-11-01'),(333,300,'2020-10-22')
SELECT date_range, SUM(fee)
FROM test
CROSS JOIN (SELECT 1 date_range UNION ALL SELECT 30) date_ranges
WHERE created_time >= CURRENT_DATE - INTERVAL date_range DAY
AND created_time < CURRENT_DATE
GROUP BY date_range
UPDATE
You may improve the performance additionally while creating date-generated subquery with interval borders, not interval lengths:
SELECT DATEDIFF(CURRENT_DATE, date_range) date_range, SUM(fee)
FROM test
CROSS JOIN (SELECT CURRENT_DATE - INTERVAL 1 DAY date_range
UNION ALL
SELECT CURRENT_DATE - INTERVAL 30 DAY) date_ranges
WHERE created_time >= date_range
AND created_time < CURRENT_DATE
GROUP BY date_range
DEMO
You can try using case when:
https://dev.mysql.com/doc/refman/5.7/en/case.html
select date_range, sum(fee)
from (
select
case
when created_time between subdate(current_date, 1) and current_date then 1
when created_time between subdate(current_date, 30) and current_date then 30
end case date_range,
fee
from test) t
where date_range is not null
group by date_range
I'm trying to get last 12 months data in Mysql using below query but i'm getting all the data not last 12 months data i gone through few of the post but helpful
My CreatedDate format is like '2020-04-17 12:03:59'
SELECT date_format(createdDate,'%m') as Month,
count(*) as count,
date_format(createdDate,'%Y') as Year
FROM tablename
WHERE DATE_ADD(Now(),INTERVAL- 12 MONTH)
GROUP BY Year,
Month
ORDER by Year desc,
Month desc;
and also need help you Insert 0 if no data found in that month.
You may use a calendar table here:
SELECT
cal.dt,
COUNT(t.createdDate) AS count
FROM
(
SELECT DATE_FORMAT(CURDATE(), '%Y-%m') AS dt UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 1 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 2 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 3 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 4 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 5 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 6 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 7 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 8 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 9 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 10 MONTH), '%Y-%m') UNION ALL
SELECT DATE_FORMAT(DATE_SUB(CURDATE(), INTERVAL 11 MONTH), '%Y-%m')
) cal
LEFT JOIN tablename t
ON cal.dt = DATE_FORMAT(createdDate, '%Y-%m')
WHERE
t.createdDate >= DATE_SUB(CURDATE(), INTERVAL 12 MONTH)
GROUP BY
cal.dt
ORDER BY
cal.dt DESC;
In MySQL 8+, you can use a recursive CTE to generate the dates:
with recursive dates as (
select curdate() - interval (1 - day(curdate())) day as yyyymm, 1 as lev
union all
select yyyymm - interval 1 month, lev + 1
from dates
where lev < 12
)
select d.yyyymm, count(t.createdDate) as cnt
from dates d left join
tablename t
on t.createdDate >= d.yyyymm and
t.createdDate < d.yyyymm + interval 1 month
group by d.yyyymm;
Note that this doesn't split the year and month into separate columns, but you can do that if you really want.
Also, this provide the current month with partial data. You can adjust the logic if you only want complete months.
This question already has answers here:
SQL Server: How to select all days in a date range even if no data exists for some days
(12 answers)
Closed 4 years ago.
In db i have comments table and for statistics i would like to get total comments count per day (last 7 days).
I use:
select date(created_at) as day, count(*) as total_comments
from comments
where DATEDIFF(NOW(), created_at) <= 7
group by day
but when there are not comments in particular day it wont return anything. How can i fill missing days?
You need a table for all the 7 days
select t1.day, t2. total_comments
from (
select 1 day from dual
union
select 2 from dual
union
select 3 from dual
union
select 4 from dual
union
select 5 from dual
union
select 6 from dual
union
select 7 from dual
) t1
left join (
select date(created_at) as day
, count(*) as total_comments
from comments where DATEDIFF(NOW(), created_at) <= 7
group by day
) t2 on t1.day = t2.day
You can use a different strategy, without the need for different tables:
select
(NOW() - INTERVAL 1 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 2 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 3 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 4 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 5 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 6 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
UNION
select (NOW() - INTERVAL 7 DAY) as day, (SELECT count(*) as total_comment from comments where date(created_at) = day ) as total_comments
i have the following mysql query , but its taking approx 5 minutes to execute, how can i decrease its execution time
select
revenue_center_group.description as rc_group,
revenue_center.description as revenue_center,
count(ytd.members) as total_ytd_members,
count(lytd.members) as total_lytd_members
from revenue_center
left join revenue_center_group on revenue_center_group.id = revenue_center.revenue_center_group_id
left join (
select membership.id as members,
membership.rc_id as rc_id
from membership
where membership.status =1
and DATE(membership.join_date)>= (SELECT DATE_FORMAT((SELECT DATE_FORMAT(date(now()) - INTERVAL 1 MONTH, '%Y-%m-%d')) ,'%Y-01-01 00:00:00'))
and DATE(membership.join_date)<= (SELECT DATE_FORMAT(LAST_DAY(date(now()) - INTERVAL 1 MONTH), '%Y-%m-%d 23:59:59'))ytd on revenue_center.id = ytd.rc_id
left join (
select
membership.id as members,
membership.rc_id as rc_id
from membership
where membership.status =1
and DATE(membership.join_date)>= (SELECT DATE_FORMAT((SELECT DATE_FORMAT((SELECT DATE_FORMAT(date(now()) - INTERVAL 1 MONTH, '%Y-%m-%d'))
- INTERVAL 1 YEAR, '%Y-%m-%d')) ,'%Y-01-01 00:00:00'))
and DATE(membership.join_date)<= (SELECT DATE_FORMAT((select DATE_FORMAT(LAST_DAY(date(now()) - INTERVAL 1 MONTH), '%Y-%m-%d')
- INTERVAL 1 YEAR),'%Y-%m-%d 23:59:59'))lytd on revenue_center.id = lytd.rc_id
group by revenue_center_group.description,revenue_center.description with rollup;
I am trying to get the amount of users signed up in the past 7 days to display on a chart and it would be nice if mysql returned 0 instead of no row. Currently it just returns a row for each day THAT has a value
SELECT date(created_at),
count(id)
FROM user_accts
WHERE date(created_at) < NOW()
AND date(created_at) > DATE_SUB(NOW(), INTERVAL 7 DAY)
GROUP BY date(created_at);
Try:
SELECT DATE_SUB(CURDATE(), INTERVAL i DAY) date_created_at,
count(id)
FROM (SELECT 1 i UNION ALL
SELECT 2 UNION ALL
SELECT 3 UNION ALL
SELECT 4 UNION ALL
SELECT 5 UNION ALL
SELECT 6 UNION ALL
SELECT 7) i
LEFT JOIN user_accts ON date(created_at) = DATE_SUB(CURDATE(), INTERVAL i DAY)
/*AND owner_id = '131'*/
GROUP BY DATE_SUB(CURDATE(), INTERVAL i DAY)