Merging together results from a UNION in sql - mysql

I am trying to combine the results of a Union from
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON'
GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON'
GROUP BY MONTH(terms)
I get the following: RESULTS FROM THE SQL STATEMENT
I am trying to make it so the total will be the combination of the multiple instances of the month.
The sql tables are exactly the same.
This Is what I would like it to look like:

A FULL OUTER JOIN would be ideal. But in your case, let's do two levels of aggregation:
SELECT month, MAX(total_projects) as total_projects, MAX(total_archive) as total_archive
FROM ((SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total_projects, 0 as total_archive
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
) UNION ALL
(SELECT MONTHNAME(terms) AS month, 0, COUNT(DISTINCT project_num
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
)
) pa
GROUP BY month
ORDER BY month;
EDIT:
Oops. You only want one column. If you want to count the number of distinct projects for each month, then do a union all and then combine the results at the next higher level:
SELECT month, COUNT(DISTINCT project_num) as total
FROM ((SELECT MONTHNAME(terms) AS month, project_num
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
) UNION ALL
(SELECT MONTHNAME(terms) AS month, project_num
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
)
) pa
GROUP BY month
ORDER BY month;

A quick thought would be to just do something like this. You essentially want to sum the counts from each table.
select month, sum(total) from
(
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM projects WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM archive WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
) group by month;

transform into a derived table, put an alias then aggregate
select
x.month,
sum(x.total) [Total]
from (
SELECT
MONTHNAME(terms) AS month,
COUNT(DISTINCT project_num) AS total
FROM projects
WHERE terms >= '2017/01/01'
AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
UNION
SELECT
MONTHNAME(terms) AS month,
COUNT(DISTINCT project_num) AS total
FROM archive
WHERE terms >= '2017/01/01'
AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
) x
group by x.month

You can try creating a sum expression on the entire query.
SELECT month, SUM (total) FROM
(SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM projects WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM archive WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms))
GROUP BY month

Related

Combine 2 SELECTS in one result Side By Side

I have 2 selects that just get the SUM of IDs and are grouped by month.. I would like to have them only on 1 SELECT - side by side...
SELECT MONTH(data) AS month, COUNT(id) AS TOTAL
FROM numeracao
WHERE data BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(DATA);
the 2nd select:
SELECT MONTH(dia) AS month, COUNT(id) AS TOTAL
FROM revisoes
WHERE dia BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(dia)
The rewsult was to be expected somethinig like this:
month
NUM
REV
1
22
4
2
52
23
...
...
...
where:
month is from 1 to 12
NUM is the sum of query 1 on table numeracao
REV is the sum of query 2 on table revisoes
You can do this by using union and then an outer aggregation:
select Month, Max(Num) Num, Max(Rev) Rev
from (
select Month(data) as month, Count(id) Num, null Rev
from numeracao
where data between '2023-01-01' and '2023-12-31'
group by Month(DATA)
union all
select Month(dia) as month, null Num, Count(id) Rev
from revisoes
where dia between '2023-01-01' and '2023-12-31'
group by Month(dia)
)t;
You can apply the inner join on the results of the aggregations to make counts appear on the same row for each month.
SELECT numtab.month,
numtab.num,
revtab.rev
FROM (SELECT MONTH(data) AS month, COUNT(id) AS num
FROM numeracao
WHERE data BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(DATA)) numtab
INNER JOIN (SELECT MONTH(dia) AS month, COUNT(id) AS rev
FROM revisoes
WHERE dia BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(dia)) revtab
ON numtab.month = revtab.month
Computing the aggregation after the inner join would bring to duplicate rows and incorrect output, given than the two tables most likely have a n-to-n association.
If you're not ensured to have at least one value for all months on both tables, you should have a month calendar table and use left join instead.
SELECT calendar.month,
numtab.num,
revtab.rev
FROM (SELECT 1 AS month UNION ALL
SELECT 2 AS month UNION ALL
SELECT 3 AS month UNION ALL
SELECT 4 AS month UNION ALL
SELECT 5 AS month UNION ALL
SELECT 6 AS month UNION ALL
SELECT 7 AS month UNION ALL
SELECT 8 AS month UNION ALL
SELECT 9 AS month UNION ALL
SELECT 10 AS month UNION ALL
SELECT 11 AS month UNION ALL
SELECT 12 AS month ) calendar
LEFT JOIN (SELECT MONTH(data) AS month, COUNT(id) AS num
FROM numeracao
WHERE data BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(DATA)) numtab
ON calendar.month = numtab.month
LEFT JOIN (SELECT MONTH(dia) AS month, COUNT(id) AS rev
FROM revisoes
WHERE dia BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(dia)) revtab
ON calendar.month = revtab.month
I wouldn't recommend this one anyways if your problem gets solved with the former query.
SELECT month,TOTAL FROM(SELECT MONTH(data) AS month, COUNT(id) AS TOTAL
FROM numeracao
WHERE data BETWEEN '2023-01-01' AND '2023-12-31'
GROUP BY MONTH(DATA)
UNION ALL
SELECT MONTH(dia) AS month, COUNT(id) AS TOTAL
FROM revisoes
WHERE dia BETWEEN '2023-01-01' AND '2023-12-31' )as rows
GROUP BY month

how to set order by in between two union querys

SELECT month,sum(pcs) as pcs,sum(carat) as carat,sum(amount) as amount from (
SELECT
DATE_FORMAT(StockInwardDate, '%b-%Y') AS Month,
COUNT(*) as pcs,
ROUND(SUM(Carat),2) as carat,
ROUND(SUM(TotalAmount),2) as amount
FROM tbl_sales
GROUP BY DATE_FORMAT(StockInwardDate, '%m-%Y')
UNION
SELECT
DATE_FORMAT(StockInwardDate, '%b-%Y') AS Month,
COUNT(*) as pcs,
ROUND(SUM(Carat),2) as carat,
ROUND(SUM(TotalAmount),2) as amount
FROM tbl_stock
GROUP BY DATE_FORMAT(StockInwardDate, '%m-%Y')
) as tbl
GROUP BY tbl.Month
ORDER by tbl.Month DESC
This above is my query but tbl.Month in order by which is equals to DATE_FORMAT(StockInwardDate, '%m-%Y') But instead of DATE_FORMAT(StockInwardDate, '%m-%Y') I want to get order by StockInwardDate only this
Is there any way to get This in order by StockInwardDate

Can I get every month of the year even if there is not data for that month in DB

I want to get a statistic for every month of the years i have in DB
SELECT monthname(created_at) AS month, YEAR(created_at) AS year, count(*) AS number
FROM tableName
WHERE type_of_user = "someType"
GROUP BY year, month(created_at)
ORDER BY created_at DESC
Now it gives me only month that I have, but I need to get statistics for every month, even if I don't have any stored data for that month
Create a calendar table. This will need one entry per month, for every year that you intend to use.
Then select from the calendar table, and join in the values that you get from your current query. Use COALESCE() to put a zero-value where the entry is NULL (e.g. when there are no records in the tableName for that month and year).
SELECT MONTHNAME(date) as month,
YEAR(date) as year,
COALESCE(number, 0) as number
FROM calendar AS C
LEFT JOIN (
SELECT created_at, COUNT(*) as number
FROM tableName AS T
WHERE T.type_of_user = 'someType'
GROUP BY YEAR(created_at), MONTH(created_at)
) AS T
ON MONTH(T.created_at) = MONTH(C.date) AND YEAR(T.created_at) = YEAR(C.date)
GROUP BY month, YEAR(created_at)
ORDER BY MONTH(date), YEAR(date)
SQL fiddle at http://sqlfiddle.com/#!9/e0a4dc/
SELECT month(created_at) as month
FROM tableName
RIGHT JOIN (select row_number() over (order by 1) as i
from someTableWithMoreThan12Records limit 12) x
ON x.i=month(created_at)
ORDER BY I;
JOINing with a table that has all the records will give you every month.

Sum of Counts from successive dates

I need to get the total number of an item for every month.
So far, with the following code :
Select Count(mpay_collector_company.id) As `Number of Collector Companies`,
Month(mpay_collector_company.created_at) As Month,
Year(mpay_collector_company.created_at) As Year
From mpay_collector_company
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at)
I have the following response :
#|Year|Month
------------
5|2014|11
3|2014|12
3|2015|1
7|2015|2
6|2015|3
2|2015|4
5|2015|6
1|2015|7
And instead of the number for each month I'd like to have the sum from the beginning for each month, which would be something like this :
Sum|Year|Month
--------------
5|2014|11
8|2014|12
11|2015|1
18|2015|2
24|2015|3
26|2015|4
31|2015|6
32|2015|7
Any ideas ?
EDIT : This request will be implemented as a view, so sub-requests are pretty much a no-go :x
Something like this could work:
Select Count(distinct previous_mpay_collector_company.id)+ Count(distinct mpay_collector_company.id) As `Number of Collector Companies`,
Month(mpay_collector_company.created_at) As Month,
Year(mpay_collector_company.created_at) As Year
From mpay_collector_company
Left Join mpay_collector_company previous_mpay_collector_company
On Year(mpay_collector_company.created_at) > Year(previous_mpay_collector_company.created_at)
OR (Month(mpay_collector_company.created_at) > Month(previous_mpay_collector_company.created_at)
And Year(mpay_collector_company.created_at) >= Year(previous_mpay_collector_company.created_at))
And previous_mpay_collector_company.id <> mpay_collector_company.id
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at);
The trick would be self joining to all of the previous months and counting from the joined table.
You can first select distinct year.months and then check count for each value
select year,month ,
( SELECT count(*) FROM mpay_collector_company WHERE
Year(mpay_collector_company.created_at) <= temp1.year
AND
Month(mpay_collector_company.created_at) <= temp1.month
)
from (
Select DISTINCT
Month(mpay_collector_company.created_at) As month,
Year(mpay_collector_company.created_at) As year
From mpay_collector_company
) as temp1
ORDER BY year,month
if you want to "reset" for each year , just change comparison to EQUAL between years and thats it
select year,month ,
( SELECT count(*) FROM mpay_collector_company WHERE
Year(mpay_collector_company.created_at) = temp1.year
AND
Month(mpay_collector_company.created_at) <= temp1.month
)
from (
Select DISTINCT
Month(mpay_collector_company.created_at) As month,
Year(mpay_collector_company.created_at) As year
From mpay_collector_company
) as temp1
ORDER BY year,month
Using a correlated subquery to count the number of rows with a date before the current should work too:
Select
Count(id) As "Number of Collector Companies",
Month(created_at) As Month,
Year(created_at) As Year,
(
Select Count(*)
From mpay_collector_company
Where EXTRACT(YEAR_MONTH from created_at) <= EXTRACT(YEAR_MONTH from m.created_at)
) as running_count
From mpay_collector_company m
Group By Year(created_at), Month(created_at);
Sample SQL Fiddle showing it in action
Select
(Select Sum(Count(Z.id)) FROM mpay_collector_company z
where z.created_at <= A.created_at) as '#',
Month(A.created_at) As Month,
Year(A.created_at) As Year
From mpay_collector_company A
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at)
This should do it for ya,

getting multi row data into columns in mysql

SELECT
Day,
month,
year,
GROUP_CONCAT(total),
GROUP_CONCAT(SP_ID)
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,l.sp_id
FROM lead_activity2 as l
right outer join salesperson as s on l.sp_id=s.sp_id
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR, DAY, l.sp_id
ORDER BY YEAR DESC, MONTH DESC, DAY DESC, l.sp_id DESC
) t GROUP BY day, month, year
http://sqlfiddle.com/#!2/1514d/3 - you can view the scheme and the query,
what i would like to get is
18 | october | 2012 | 0,0,1,1 | 6,5,4,3
spid 6 and spid 5 have no data for 18 october but still should be shown tried doing right join and right outer join both dont seem to work...
Use GROUP_CONCAT like so:
SELECT
Day,
month,
year,
GROUP_CONCAT(total),
GROUP_CONCAT(SP_ID)
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,l.sp_id
FROM lead_activity2 as l
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR, DAY, l.sp_id
ORDER BY YEAR DESC, MONTH DESC, DAY DESC, l.sp_id DESC
) t GROUP BY day, month, year
Updated SQL Fiddle
Update: Yes you can do this, but use LEFT JOIN to include non matching sp_id. These non matching ids will have a value of NULL use IFNULL to display it with zeros like so:
SELECT
Day,
month,
year,
GROUP_CONCAT(total) Total,
GROUP_CONCAT(SP_ID) 'List of sp_ids'
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,
IFNULL(s.sp_id , 0) sp_id
FROM lead_activity2 as l
LEFT JOIN salesperson s ON l.sp_id = s.sp_id
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR,DAY,s.sp_id
) t
ORDER BY YEAR DESC,
MONTH DESC,
DAY DESC,
sp_id DESC
Updates SQL Fiddle Demo