MySQL UNION does not seem to work correctly - mysql

I have an SQL query I am using to pull data from an orders database. I am querying 2 tables and combining the results using UNION ALL. However, the UNION ALL does not seem to work as expected. Here is the query I am using:
SELECT year(oc_order.date_added) AS year, COUNT(oc_order.order_id) as cnt, SUM( ifnull(oc_order.new_total,oc_order.total) ) as total
FROM oc_order
WHERE oc_order.order_status_id IN (1,3,5)
AND MONTH(oc_order.date_added) BETWEEN '01' AND '02'
AND DAY(oc_order.date_added) BETWEEN '01' AND '31'
GROUP BY year(oc_order.date_added)
UNION ALL
SELECT ifnull(year(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),year(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) AS year, COUNT(oc_return_custom.return_id) as cnt, SUM( oc_return_custom.total ) as total
FROM oc_return_custom
WHERE ifnull(MONTH(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),MONTH(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) BETWEEN '01' AND '02'
AND ifnull(DAY(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),DAY(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) BETWEEN '01' AND '31'
GROUP BY ifnull(year(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),year(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) )
ORDER BY year DESC
This is what I get from the query:
+=======+========+=======+
| year | cnt | total |
+=======+========+=======+
| 2016 | 200 | 1000 |
| 2016 | 50 | 200 |
| 2015 | 100 | 800 |
| 2015 | 10 | 50 |
+=======+========+=======+
But this is what I wanted to get:
+=======+========+=======+
| year | cnt | total |
+=======+========+=======+
| 2016 | 250 | 1200 |
| 2015 | 110 | 850 |
+=======+========+=======+
Can someone tell me what I am doing wrong???
Notes:
The oc_order table's date_added column is datetime whereas oc_return_custom 's date_added column is just text.

UNION ALL simply puts together two data sets produced by separate GROUP BY operations.
To get the expected result set you have to wrap the query in a subquery and apply an additional GROUP BY:
SELECT year, SUM(cnt) AS cnt, SUM(total) AS total
FROM ( ... your query here ...) AS t
GROUP BY year

Related

mysql inner join two tables with month matching

I have a two tables in MySQL and both tables in same database.
table name data
| service | count | date |
--------------------------------------
| bugss | 375 | 2022-01-01 05:00:00.00000
| fromsite | 5 | 2022-02-01 05:00:00.00000
| kbocetra | 100 | 2022-01-05 07:00:00.00000
tried for data table
SELECT SUM(`count`) AS Alertcount,
DATE_FORMAT(`date`, '%M') AS Month,
FROM data
GROUP BY DATE_FORMAT(`date`, '%Y-%m')
output:
January | 475
February | 5
another table name pd
| group | minutes | projdate |
--------------------------------
gcp | 145 | 2022-01-01 05:00:00.00000
azure | 10 | 2022-02-01 05:00:00.00000
aws | 80 | 2022-01-05 07:00:00.00000
i tried below command for separate tables, for pd table as below ..which gives output as
SELECT SUM(`minutes`) AS Hours,
DATE_FORMAT(`group `, '%M') AS Month
FROM pd
GROUP BY DATE_FORMAT(`group`, '%Y-%m')
output:
January | 225
February | 10
and im expected the ouput like below, and total count would be as output of two tables count/minutes i.e., 475/225
and 5/10.
please help, i red about inner statement, but didn't worked.
Month
total
January
0.78
February
2
Run the following command and see the results.
SELECT
a.`Month`,
a.`Hours` / b.`Alertcount` as 'total'
FROM
(
SELECT
SUM( `minutes` ) AS Hours,
DATE_FORMAT( `group `, '%M' ) AS 'Month'
FROM
pd
GROUP BY
DATE_FORMAT( `group`, '%Y-%m' )
) a
INNER JOIN (
SELECT
SUM( `count` ) AS Alertcount,
DATE_FORMAT( `date`, '%M' ) AS 'Month'
FROM
DATA
GROUP BY
DATE_FORMAT( `date`, '%Y-%m' )
) b ON a.`Month` = b.`Month`
When selecting the tables you can use the division operator as you can see here.

The division of each row by the sum of the rows that has the same value of two columns

I want to calculate the division of each row per the sum of all rows that have the same Dateadded and fundid, but it seems my query is wrong due the results is not what I was expecting.
My table schema looks like this, I avoided mine because it has many more columns:
+----+--------+------------+--------+
| id | fundid | Dateadded | amount |
+====+========+============+========+
| 1 | 45 | 21-02-2018 | 5412 |
| 2 | 45 | 21-02-2018 | 5414 |
| 3 | 45 | 21-02-2018 | 1412 |
| 4 | 45 | 22-02-2018 | 5756 |
| 5 | 45 | 22-02-2018 | 4412 |
| 6 | 45 | 25-02-2018 | 2532 |
| 7 | 45 | 26-02-2018 | 7892 |
| 8 | 45 | 26-02-2018 | 8143 |
+----+-------+-------------+--------+
Rows with id's: 1,2,3 should be calculated together because they have
the same fundid and date.
Rows with id's: 4,5 same thing.
Rows with id's: 6 it is just one.
Rows with id's: 7,8 same thing.
My SQL query:
SELECT fundid
, Dateadded
, ( amount / SUM(amount) ) AS AvgRow
FROM stock2
GROUP
BY fundid
, Dateadded
ORDER
BY DateAdded ASC
Is this what you want?
select t.*, t.amount / tt.total_amount
from stock2 t join
(select fundid, dateadded, sum(amount) as total_amount
from stock2 t
group by fundid, dateadded
) tt
using (fundid, dateadded);
Or is this?
select fundid, dateadded, sum(t.amount) / tt.total_amount
from stock2 t cross join
(select sum(amount) as total_amount
from stock2 t
) tt
group by fundid, dateadded, tt.total_amount;
Check out a very well explained response to a similar issue related to usage of Group by here).
Similarly to the situation described there, for your query is ambiguous re: what "amount" should be used for each row. I.e. if you try:
SELECT fundid, Dateadded, ( AVG(amount) / SUM(amount) ) AS AvgRow FROM stock2 GROUP BY fundid, Dateadded ORDER BY DateAdded ASC
it will work because AVG(amount) is non-ambiguous for each (fundid, Dateadded) pair that should be calculated together.
It seems you are looking for something like:
SELECT st.fundid, st.Dateadded, ( amount / st2.total) ) AS AvgRow
FROM stock2 st
inner join
(select fundid, Dateadded, sum(amount) as total
from stock2
GROUP BY fundid, Dateadded) st2
on st.fundid = st2.fundid and st.Dateadded = st2.Dateadded
order by st.Dateadded

How to group by month and return zero if no value for certain month?

This is my mysql income table.
+----+------------------+---------------------------+------------+---------+
| id | title | description | date | amount |
+----+------------------+---------------------------+------------+---------+
| 1 | Vehicle sales up | From new sale up | 2016-09-09 | 9999.99 |
| 2 | Jem 2 Sales | From rathnapura store | 2016-05-15 | 9545.25 |
| 3 | Jem 2 Sales 2 | From rathnapura store | 2016-05-15 | 9545.25 |
| 4 | Jem 2 Sales 2 | From rathnapura store 234 | 2016-05-15 | 9545.25 |
+----+------------------+---------------------------+------------+---------+
The field 'date' is standard sql date. And I executed this query in order to take sum of incomes by month and return zero if no income from a certain month. I want zeros if no income from a certain month because i want to display these data in a chart.
This is the query.
SELECT MONTHNAME(`date`) AS mName, MONTH(`date`) AS mOrder, ifnull(sum(amount),0) AS total_num FROM income GROUP BY mOrder ORDER BY mOrder DESC
But I only get a output like follows. No zeros if no values in other months. This is the output.
+-----------+--------+-----------+
| mName | mOrder | total_num |
+-----------+--------+-----------+
| September | 9 | 9999.99 |
| May | 5 | 28635.75 |
+-----------+--------+-----------+
And I want other months in above table and total_num as zero. How can I do this? There's same kind of question there too. But no working answer.
Group by month and return 0 if data not found
Please help me to solve this issue. The language I use for this application is Node.JS :)
Have a table of all the months and then left join to your table:
SELECT MONTHNAME(m.month) AS mName,
MONTH(m.month) AS mOrder,
ifnull(sum(amount),0) AS total_num
from months m
left join income i
on m.month = i.date
GROUP BY mOrder
ORDER BY mOrder DESC
If you don't want to create a months table then you can:
(select STR_TO_DATE('01/01/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/02/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/03/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/04/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/05/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/06/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/07/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/08/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/09/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/10/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/11/2016', '%d/%m/%Y') as month union
select STR_TO_DATE('01/12/2016', '%d/%m/%Y') as month)
You should create a CALENDAR table, with the precision you need, in this case months.
+-----------+
| Month |
+-----------+
| January |
| February |
.......
And Join on it
Maybe this it's not the best way to do it, but it will solve your problem. As a quick soution:
SELECT 'January' AS mName, 1 AS mOrder, COALESCE(SUM(amount),0) AS total_num
FROM income i
WHERE month(i.date) = 1
UNION
SELECT 'February' AS mName, 2 AS mOrder, COALESCE(SUM(amount),0) AS total_num
FROM income i
WHERE month(i.date) = 2
UNION
...and go on

SUM a pair of COUNTs from two tables based on a time variable

Been searching for an answer to this for the better part of an hour without much luck. I have two regional tables laid out with the same column names and I can put out a result list for either table based on the following query (swap Table2 for Table1):
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
Ideally I'd like to get a result that gives me a total sum of the counts by year, so instead of:
| REGION 1 | | REGION 2 |
| YEAR | Total | | YEAR | Total |
| 2010 | 5 | | 2010 | 1 |
| 2009 | 2 | | 2009 | 3 |
| | | | 2008 | 4 |
I'd have:
| MERGED |
| YEAR | Total |
| 2010 | 6 |
| 2009 | 5 |
| 2008 | 4 |
I've tried a variety of JOINs and other ideas but I think I'm caught up on the SUM and COUNT issue. Any help would be appreciated, thanks!
SELECT `YEAR`, FORMAT(SUM(`count`), 0) AS `Total`
FROM (
SELECT `Table1`.`YEAR`, COUNT(*) AS `count`
WHERE `Table1`.`variable` = 'Y'
GROUP BY `Table1`.`YEAR`
UNION ALL
SELECT `Table2`.`YEAR`, COUNT(*) AS `count`
WHERE `Table2`.`variable` = 'Y'
GROUP BY `Table2`.`YEAR`
) AS `union`
GROUP BY `YEAR`
You should use an UNION:
SELECT
t.YEAR,
COUNT(*) as TOTAL
FROM (
SELECT *
FROM Table1
UNION ALL
SELECT *
FROM Table2
) t
WHERE t.variable='Y'
GROUP BY t.YEAR;
Select year, sum(counts) from (
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, FORMAT(COUNT(Table2.id),0) AS Total
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) GROUP BY year
To improve upon Shehzad's answer:
SELECT YEAR, FORMAT(SUM(counts),0) AS total FROM (
SELECT Table1.YEAR, COUNT(Table1.id) AS counts
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, COUNT(Table2.id) AS counts
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) AS newTable GROUP BY YEAR

Sql query to extract average grouped by a column

I'm trying to generate a SQL query to extract an average montly powerusage (of a year) for an ID.
+----+------------+------------+
| id | powerusage | date |
+----+------------+------------+
| 1 | 750 | 2011-12-2 |
| 1 | 1000 | 2011-12-1 |
| 1 | 1500 | 2011-11-15 |
| 1 | 100 | 2011-11-13 |
| 1 | 50 | 2011-11-10 |
| 2 | 500 | 2011-11-15 |
| 2 | 200 | 2011-11-13 |
+----+------------+------------+
So if ID = 1 I want (avg november + avg december) / 2 = (1750/2 + 1650/3) / 2 = 712.5
select AVG(powerusage) as avgMontlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011
But this will give me 680.
How do I do a average on a group?
Many thanks for all the answers! But I see my question is incorrect. See updated question
Something like
select AVG(montlyPowerUsage) from (
SELECT MONTH(date) as mnth,sum(powerusage) as montlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011 group by MONTH(date)
) t1
For Edited question
select AVG(montlyPowerUsage) from (
SELECT MONTH(date) as mnth,AVG(powerusage) as montlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011 group by MONTH(date)
) t1
mysql> select avg(powerusage)
from
(select monthname(date), sum(powerusage) as powerusage
from usagetable
where id=1 and year(date)=2011
group by monthname(date)) as avg_usage;
+-----------------+
| avg(powerusage) |
+-----------------+
| 1700.0000 |
+-----------------+
select avg(total_powerusage)
from
(select monthname(date), sum(powerusage) as total_powerusage
from usagetable
where id=1 and year(date)=2011
group by monthname(date)
) as avg_usage;
/* the use of subquery
is to return total of unique occurrences,
and sum powerusage of each occurrence,
which mean, you just need to apply AVG into the subquery */
This should give you monthly averages for every year and user. Some of the syntax may be MS SQL specific, but the logic should be good.
SELECT id, AVG(usage), year FROM
(SELECT id, SUM(powerusage) as usage, YEAR(date) as Year, MONTH(date) as Month
FROM usagetable
GROUP BY id, YEAR(date), MONTH(date)) as InnerTable
GROUP BY id, year
Try adding a group by on the id
GROUP BY id
Or the date, whichever suits.
SELECT SUM(powerusage) / (MONTH(MAX(`date`)) - MONTH(MIN(`date`)) + 1)
AS avgMontlyPowerUsage
FROM usagetable
WHERE id = 1
AND YEAR(`date`) = 2011
or (depending on what you need when data is sparse):
SELECT SUM(powerusage) / COUNT( DISTINCT MONTH(`date`) )
AS avgMontlyPowerUsage
FROM usagetable
WHERE id = 1
AND YEAR(`date`) = 2011
Warning: Neither of the above is optimized for performance.