How to combine the results of two MySQL queries into one? - mysql

Suppose I have a table like this:
How can I count the number of data that occur at the day of 2018-09-07 for each person, and the number of data that occur at the month 2018-09 for each person?
I mean I want to create a table like this:
I know that
SELECT
name,
COUNT(*) AS day_count_2018_09_07
FROM data_table
WHERE
arrive_time >= '2018-09-07 00:00:00'
AND
arrive_time <= '2018-09-07 23:59:59'
GROUP BY name;
can generate the number of data that occur at the day of 2018-09-07 for each person, and
SELECT
name,
COUNT(*) AS month_count_2018_09
FROM data_table
WHERE
arrive_time >= '2018-09-01 00:00:00'
AND
arrive_time <= '2018-09-30 23:59:59'
GROUP BY name;
can generate the number of data that occur at the month 2018-09 for each person.
But I don't know how to combine the above two queries so that day_count_2018_09_07 and month_count_2018_09 columns can be created in one query.
Here's the SQL fiddle where you can directly get the data in my question.

You can use conditional aggregation to get both results from the same query:
SELECT name,
SUM(CASE WHEN SUBSTR(DATE(arrive_time),1,7)='2018-09' THEN 1 ELSE 0 END) AS month_count_2018_09,
SUM(CASE WHEN DATE(arrive_time)='2018-09-07' THEN 1 ELSE 0 END) AS day_count_2018_09_07
FROM data_table
GROUP BY name
Output:
name month_count_2018_09 day_count_2018_09_07
Ben 3 0
Jane 1 1
John 3 2

Try to combine them like that:
Select DayCounter.name, DayCounter.day_count_2018_09_07, MonthCounter.month_count_2018_09
from
(SELECT
name,
COUNT(*) AS day_count_2018_09_07
FROM data_table
WHERE
arrive_time >= '2018-09-07 00:00:00'
AND
arrive_time <= '2018-09-07 23:59:59'
GROUP BY name) as DayCounter
Inner Join
(SELECT
name,
COUNT(*) AS month_count_2018_09
FROM data_table
WHERE
arrive_time >= '2018-09-01 00:00:00'
AND
arrive_time <= '2018-09-30 23:59:59'
GROUP BY name) as MonthCounter
On DayCounter.name = MonthCounter.name

What about something like this:
SELECT
name,
SUM(CASE WHEN (arrive_time BETWEEN '2018-09-07 00:00:00' AND '2018-09-07 23:59:59') THEN 1 ELSE 0 END) AS day_count_2018_09_07,
SUM(CASE WHEN (arrive_time BETWEEN '2018-09-01 00:00:00' AND '2018-09-30 23:59:59') THEN 1 ELSE 0 END) AS month_count_2018_09
FROM
data_table
GROUP BY
name;

Related

sql group by with double conditions

I need to get the amount of distinct parent_ids that fill in one of the conditions below , grouped by day:
parent_ids that have both status = pending & processing
OR
parent_ids who have both status = canceled and processing.
I ve tried something similar to :
SELECT count(parent_id) as pencan, created_at, DATE_FORMAT(a.created_at, '%Y') AS year_key, DATE_FORMAT(a.created_at, '%m-%d') as day_key
FROM sales_flat_order_status_history
where created_at BETWEEN '2010-01-01 00:00:00' AND '2013-04-30 23:59:59'
GROUP BY created_at ,parent_id
HAVING SUM(status = 'processing')
AND SUM(status IN ('pending', 'cancelling'))
I think you just need to fix the group by:
SELECT DATE(created_at), count(parent_id) as pencan
FROM sales_flat_order_status_history
where created_at >= '2010-01-01' AND
created_at < '2013-05-01'
GROUP BY DATE(created_at) , parent_id
HAVING SUM(status = 'processing') AND
SUM(status IN ('pending', 'cancelling'))

MySQL error getting total values between two dates and another filter

I want to get SUM values from a table between two dates but I have another filter also. I am getting syntax error and could not find what is wrong. This is the SQL sentence:
SUM(IF((date BETWEEN '2020-01-01 00:00:00' AND '2020-01-31 23:59:59') AND ql=1),total,0) AS t1q1,
SUM(IF((date BETWEEN '2020-01-01 00:00:00' AND '2020-01-31 23:59:59') AND ql=2),total,0) AS t1q2,
SUM(IF((date BETWEEN '2019-12-01 00:00:00' AND '2019-12-31 23:59:59') AND ql=1),total,0) AS t2q1,
SUM(IF((date BETWEEN '2019-12-01 00:00:00' AND '2019-12-31 23:59:59') AND ql=2),total,0) AS t2k2
FROM myTable
GROUP BY productID
ORDER BY productID ASC
SELECT
SUM(case when date>='2020-01-01' and date<'2020-02-01' AND ql=1 then total else 0 end) t1q1,
SUM(case when date>='2020-01-01' and date<'2020-02-01' AND ql=2 then total else 0 end) t1q2,
SUM(case when date>='2019-12-01' and date<'2020-01-01' AND ql=1 then total else 0 end) t2q1,
SUM(case when date>='2019-12-01' and date<'2020-01-01' AND ql=2 then total else 0 end) t2q2
FROM myTable
GROUP BY productID
ORDER BY productID ASC

SQL query summary issue

I'm new to SQL and trying to create a total summary of a working SQL query. It's listing the total results from one month of data.
Now I need the total values of the outcome of the query.
So I created a 'query in a query' piece of SQL, but it ain't working because my lack of SQL knowledge. I guess it's an easy fix for you pro's :-)
The working SQL query with the daily outcome of one month:
SELECT
DATE_FORMAT(date, '%d/%m/%y') AS Datum,
COUNT(*) AS Berichten,
SUM(CASE WHEN virusinfected>0 THEN 1 ELSE 0 END) AS Virus,
SUM(CASE WHEN (virusinfected=0 OR virusinfected IS NULL) AND isspam>0 THEN 1 ELSE 0 END) AS Ongewenst,
SUM(CASE WHEN (virusinfected=0 OR virusinfected IS NULL) AND (isspam=1) AND isrblspam>0 THEN 1 ELSE 0 END) AS RBL,
SUM(size) AS Grootte
FROM
maillog
WHERE
1=1
AND (1=1)
AND
date < '2017-04-01'
AND
date >= '2017-03-01'
AND
to_domain = 'domain1.nl'
OR
date < '2017-04-01'
AND
date >= '2017-03-01'
AND
to_domain = 'domain2.nl'
GROUP BY
Datum
ORDER BY
date
The incorrect query trying to create the monthly totals:
SELECT Datum,
SUM(Berichten) AS Berichten,
SUM(Virus) AS Virus,
SUM(Ongewenst) AS Ongewenst,
SUM(RBL) AS RBL,
SUM(Grootte) AS Grootte,
FROM ( SELECT
DATE_FORMAT(date, '%d/%m/%y') AS Datum,
COUNT(*) AS Berichten,
SUM(CASE WHEN virusinfected>0 THEN 1 ELSE 0 END) AS Virus,
SUM(CASE WHEN (virusinfected=0 OR virusinfected IS NULL) AND isspam>0 THEN 1 ELSE 0 END) AS Ongewenst,
SUM(CASE WHEN (virusinfected=0 OR virusinfected IS NULL) AND (isspam=1) AND isrblspam>0 THEN 1 ELSE 0 END) AS RBL,
SUM(size) AS Grootte
FROM
maillog
WHERE
1=1
AND (1=1)
AND
date < '2017-04-01'
AND
date >= '2017-03-01'
AND
to_domain = 'domain1.nl'
OR
date < '2017-04-01'
AND
date >= '2017-03-01'
AND
to_domain = 'domain2.nl'
GROUP BY
Datum
ORDER BY
date
) t
GROUP BY Datum;
Thanks in advance.
What you want can be done with just a little addition to your first SQL statement: add with rollup after the group by clause:
GROUP BY Datum WITH ROLLUP
It will run more efficiently than the version with sub-query, although it could work that way, but you should then remove the outer group by clause and not select Datum there, since you don't want the totals per date any more, but overall.
Still, you will lose the details and only get the overall totals then. You would have to use a union with your original query to get both levels of totals. You can imagine that the with rollup modifier will do the job more efficiently.

Get records with difference on 2 different date ranges in single query

I have sales table and have two different date ranges.
i.e, I have total sales between (2016-12-21 - 2016-12-30) is 100 and for period (2016-12-11 - 2016-12-20) is 85.
Now the result I want is
100 (sales of 2016-12-21 - 2016-12-30), 85 (sales of 2016-12-11 - 2016-12-20), 15 (difference of both periods) through single query.
What I am thinking is
select *, (a.sales - b.sales) as diff
from (select id, sum(sales) as sales from salestable where date >= '2016-12-21' and date <= '2016-12-30') a
join (select id, sum(sales) as sales from salestable where date >= '2016-12-11' and date <= '2016-12-20') b
on a.id = b.id;
Is there any other better way to do this?
You can use conditional aggregation:
select sum(case when date >= '2016-12-21' and date <= '2016-12-30' then sales else 0
end) as sales_a,
sum(case when date >= '2016-12-11' and date <= '2016-12-20' then sales else 0
end) as sales_b,
sum(case when date >= '2016-12-21' and date <= '2016-12-30'
then sales else 0
when date >= '2016-12-11' and date <= '2016-12-20'
then -sales
else 0
end) as sales_diff
from salestable;
If you want the overall sum by id (as suggested by your inclusion of id), then add id to the select and add group by id.
You can use case to do a conditional sum like this:
select id,
sum_21_to_30,
sum_11_to_20,
sum_21_to_30 - sum_11_to_20 diff
from (select id,
sum(case when date >= '2016-12-21' and date <= '2016-12-30' then sales else 0 end) sum_21_to_30,
sum(case when date >= '2016-12-11' and date <= '2016-12-20' then sales else 0 end) sum_11_to_20
from table group by id) t;

What's the most efficient way of operating with fields in MySQL?

I have the following query:
SELECT DATE(utimestamp) as utimestamp, name, data*2000000 from tData
where utimestamp BETWEEN '2016-01-01 00:00:00' AND '2016-04-16 00:00:00'
AND name = 'Valor2' and data>20
group by YEAR(utimestamp), MONTH(utimestamp), name
union
SELECT DATE(utimestamp) as utimestamp, name, data*0.1 from tData
where utimestamp BETWEEN '2016-01-01 00:00:00' AND '2016-04-16 00:00:00'
AND name = 'Valor1' and data>20
group by YEAR(utimestamp), MONTH(utimestamp), name
order by utimestamp asc
Is there a more efficient way of operating with 'data'? Is there a way of doing this without using UNION?
You can try to use case when then:
SELECT DATE(utimestamp) as utimestamp, name,
case when name = 'Valor1' then data*0.1
when name = 'Valor2' then data*2000000
end
from tData
where utimestamp BETWEEN '2016-01-01 00:00:00' AND '2016-04-16 00:00:00'
and data>20
group by YEAR(utimestamp), MONTH(utimestamp), name
order by utimestamp asc
The query in your question is strange, because it has a math calculation without an aggregation function. And, you are aggregating by year and month, but not including them in the query.
I would be inclined to put the values in two separate columns, with the year and month explicitly defined in the query:
select year(utimestamp), month(utimestamp),
sum(case when name = 'Valor1' then data*0.01 end) as valor1,
sum(case when name = 'Valor2' then data*2000000 end) as valor2
from tData
where utimestamp between '2016-01-01' and '2016-04-16' and
name in ('Valor1', 'Valor2') and
data > 20
group by year(utimestamp), month(utimestamp)
order by max(utimestamp);