I have a table name as JOB_Details and the data show as below:
Employee_ID Age Department Gender
001 30yrs IT M
002 34yrs HR F
003 39yrs HR F
004 49yrs Finance M
005 54yrs IT M
006 20yrs HR M
007 24yrs HR F
008 33yrs Finance F
009 29yrs Finance F
010 44yrs IT M
The output i wish to display should be like
Age Department:IT Department:Finance Department:HR Total
Male Female Male Female Male Female
<30yrs 1 0 0 1 1 1 4
30-34yrs 0 0 0 1 0 1 2
35-39yrs 0 0 0 0 0 1 1
40-49yrs 1 0 1 0 0 0 2
50-54yrs 1 0 0 0 0 0 1
Total 3 0 1 2 1 3 10
Based on my knowledge, the only way can be done it is by create another view and group them one by one. But i wish to know is that other way to do it without create a other view? I wish to learn it if anyone have other good suggestion. Thank you very much.
MySQL version. Will not work in SQL Server neither Oracle. SQL Fiddle
select *, IT_Male + IT_Female + Finance_Male + Finance_Female + HR_Male + HR_Female as Total
from (
select
ar.`range` as Age,
count(Department = 'IT' and Gender = 'M' or null) as IT_Male,
count(Department = 'IT' and Gender = 'F' or null) as IT_Female,
count(Department = 'Finance' and Gender = 'M' or null) as Finance_Male,
count(Department = 'Finance' and Gender = 'F' or null) as Finance_Female,
count(Department = 'HR' and Gender = 'M' or null) as HR_Male,
count(Department = 'HR' and Gender = 'F' or null) as HR_Female
from
JOB_Details jd
inner join
age_range ar on jd.Age between ar.bottom and ar.top
group by ar.`range`
order by ar.bottom
) s
union
select
'Total',
count(Department = 'IT' and Gender = 'M' or null),
count(Department = 'IT' and Gender = 'F' or null),
count(Department = 'Finance' and Gender = 'M' or null),
count(Department = 'Finance' and Gender = 'F' or null),
count(Department = 'HR' and Gender = 'M' or null),
count(Department = 'HR' and Gender = 'F' or null),
count(*)
from JOB_Details
Oracle version without external table or view: SQL Fiddle
with age_range as (
select 0 as "bottom", 29 as "top", '<30' as "range" from dual union
select 30, 34, '30-34' from dual union
select 35, 39, '35-59' from dual union
select 40, 49, '40-49' from dual union
select 50, 54, '50-54' from dual
)
select s.*, IT_Male + IT_Female + Finance_Male + Finance_Female + HR_Male + HR_Female as Total
from (
select
ar."range" as Age,
count(case when Department = 'IT' and Gender = 'M' then 1 end) as IT_Male,
count(case when Department = 'IT' and Gender = 'F' then 1 end) as IT_Female,
count(case when Department = 'Finance' and Gender = 'M' then 1 end) as Finance_Male,
count(case when Department = 'Finance' and Gender = 'F' then 1 end) as Finance_Female,
count(case when Department = 'HR' and Gender = 'M' then 1 end) as HR_Male,
count(case when Department = 'HR' and Gender = 'F' then 1 end) as HR_Female
from
JOB_Details jd
inner join
age_range ar on jd.Age between ar."bottom" and ar."top"
group by ar."range", ar."bottom"
order by ar."bottom"
) s
union
select
'Total',
count(case when Department = 'IT' and Gender = 'M' then 1 end),
count(case when Department = 'IT' and Gender = 'F' then 1 end),
count(case when Department = 'Finance' and Gender = 'M' then 1 end),
count(case when Department = 'Finance' and Gender = 'F' then 1 end),
count(case when Department = 'HR' and Gender = 'M' then 1 end),
count(case when Department = 'HR' and Gender = 'F' then 1 end),
count(*)
from JOB_Details
SELECT
CASE WHEN Age < 30 THEN '<30'
WHEN 30 <= Age AND Age < 34 THEN '30-34'
...
END as Age,
SUM(CASE WHEN Department = 'IT' AND Gender = 'M' THEN 1 ELSE 0) END AS IT_M,
SUM(CASE WHEN Department = 'IT' AND Gender = 'F' THEN 1 ELSE 0) END AS IT_F,
...
FROM JOB_DETAILS
GROUP BY
CASE WHEN Age < 30 THEN '<30y'
WHEN 30 <= Age AND Age < 34 THEN '30-34'
...
END
Related
I am having three tables financial_year, house_details, consumer_details. I need to get the sum of each tax group by year and subincome. My table and query is in this link: sqlfiddle
Getting Result:
Name house_number address subincome financial_year gtax htax LTAX
--------------------------------------------------------------------------
Bala 22 Mumbai Garbage tax 2015-2016 200 NULL NULL
Bala 22 Mumbai Garbage tax 2016-2017 250 NULL NULL
Bala 22 Mumbai House tax 2015-2016 NULL 0 NULL
Bala 22 Mumbai House tax 2016-2017 NULL 145 NULL
Bala 22 Mumbai Light tax 2015-2016 NULL NULL 510
Bala 22 Mumbai Light tax 2016-2017 NULL NULL 200
Expecting Result:
Name house_number address gtax htax LTAX
--------------------------------------------------------
Bala 22 Mumbai 450 145 710
You are looking for conditional aggregation note this solution only works if there is an entry for each subincome(tax type)in house details for each financial year.
SELECT c.consumer_name as Name, c.house_number, c.address,
sum(CASE WHEN h.subincome = 'Garbage tax' THEN f.garbage_tax else 0 end) -
sum(CASE WHEN h.subincome = 'Garbage tax' THEN h.rupees else 0 END) as gtax,
sum(CASE WHEN h.subincome = 'House tax' THEN f.house_tax else 0 end) -
sum(CASE WHEN h.subincome = 'House tax' THEN h.rupees else 0 END) as htax,
sum(CASE WHEN h.subincome = 'Light tax' THEN f.light_tax else 0 end) -
sum(CASE WHEN h.subincome = 'Light tax' THEN h.rupees else 0 END) as LTAX
from house_details h
INNER JOIN financial_year f ON h.financial_year = f.year AND h.house_id = f.house_number
INNER JOIN consumer_details c ON h.house_id = c.house_number AND h.financial_year != '2017-2018'
group by c.consumer_name , c.house_number, c.address
result
+------+--------------+---------+------+------+------+
| Name | house_number | address | gtax | htax | LTAX |
+------+--------------+---------+------+------+------+
| Bala | 22 | Mumbai | 450 | 145 | 710 |
+------+--------------+---------+------+------+------+
1 row in set (0.03 sec)
If it is not guaranteed that there will be an entry for every subincome in every financial year then the the solution has to be driven from the tax due table (financial year) which in my view is badly designed ,inflexible and forces a sub optimal solution
select c.consumer_name as Name, s.house_number, c.address,
sum(case when subincome = 'garbage tax' then taxdue else 0 end) - sum(case when subincome = 'garbage tax' then taxpaid else 0 end) as gtax,
sum(case when subincome = 'house tax' then taxdue else 0 end) - sum(case when subincome = 'house tax' then taxpaid else 0 end) as htax,
sum(case when subincome = 'light tax' then taxdue else 0 end) - sum(case when subincome = 'light tax' then taxpaid else 0 end) as ltax
from
(
SELECT F.`house_number`, F.`year`, F.`house_tax` taxdue, F.`createdAt`, F.`updatedAt`,ifnull(h.subincome,'house_tax') subincome,ifnull(H.RUPEES,0) taxpaid
FROM FINANCIAL_YEARS F
LEFT JOIN house_details H ON H.HOUSE_ID = F.HOUSE_NUMBER AND H.SUBINCOME = 'house tax' and f.year = h.financial_year
#where f.house_number = 22
union all
SELECT F.`house_number`, F.`year`, F.`light_tax`, F.`createdAt`, F.`updatedAt`,ifnull(h.subincome,'light tax'),ifnull(H.RUPEES,0)
FROM FINANCIAL_YEARS F
LEFT JOIN house_details H ON H.HOUSE_ID = F.HOUSE_NUMBER AND H.SUBINCOME = 'light tax' and f.year = h.financial_year
#where f.house_number = 2
union all
SELECT F.`house_number`, F.`year`, F.`garbage_tax`, F.`createdAt`, F.`updatedAt`,ifnull(h.subincome,'garbage tax'),ifnull(H.RUPEES,0)
FROM FINANCIAL_YEARS F
LEFT JOIN house_details H ON H.HOUSE_ID = F.HOUSE_NUMBER AND H.SUBINCOME = 'garbage tax' and f.year = h.financial_year
#where f.house_number = 2
) s
join consumer_details c on s.house_number = c.house_number
where s.year <> '2017-2018'
group by c.consumer_name , s.house_number, c.address
Try this it will give exact result which you want, I just create a drive table and then sum
SELECT name
, house_number
, address
, SUM(gtax) as gtax
, SUM(htax) as htax
, SUM(LTAX) LTAX
FROM (SELECT c.consumer_name as Name
, c.house_number
, c.address,h.subincome
, h.financial_year
, CASE WHEN h.subincome = 'Garbage tax' THEN f.garbage_tax - sum(h.rupees)END as gtax
, CASE WHEN h.subincome = 'House tax' THEN f.house_tax - sum(h.rupees) END as htax
, CASE WHEN h.subincome = 'Light tax' THEN f.light_tax - sum(h.rupees) END as LTAX
FROM house_details h
INNER JOIN financial_year f ON h.financial_year = f.year AND h.house_id = f.house_number
INNER JOIN consumer_details c ON h.house_id = c.house_number AND h.financial_year != '2017-2018'
GROUP BY h.subincome, h.financial_year) as main
GROUP BY house_number
then result is :
I have a query that works but in addition to what I already have I want to add one extra column for each category free,reduced,paid and certified free with the percentage compared to the total number of students. Can anyone help me?
select
count(case when Lunchstatus = 'P' then 1 else null end) as Paid
, count(case when LunchStatus = 'R' then 1 else null end) as Reduced
, count(case when LunchStatus = 'F' then 1 else null end) as Free
, count(case when LunchStatus = 'fdc' then 1 else null end) as CertifiedFree
, count(case when LunchStatus = 'P' then 1
when LunchStatus = 'fdc' then 1
when LunchStatus = 'R' then 1
when LunchStatus = 'F' then 1
else null
end) as Total
from students
where enroll_status = 0
and schoolid = %param1%
Treat you existing query as a derived table, cross join for the total count, then calculate your percentages:
select
d.*
, d.Paid * 100.0 / cj.totcount as paid_pct
... more like that
from (
select
count(case when Lunchstatus = 'P' then 1 else null end) as Paid
, count(case when LunchStatus = 'R' then 1 else null end) as Reduced
, count(case when LunchStatus = 'F' then 1 else null end) as Free
, count(case when LunchStatus = 'fdc' then 1 else null end) as CertifiedFree
, count(case when LunchStatus = 'P' then 1
when LunchStatus = 'fdc' then 1
when LunchStatus = 'R' then 1
when LunchStatus = 'F' then 1
else null
end) as Total
from students
where enroll_status = 0
and schoolid = %param1%
) d
CROSS JOIN (
select count(*) as totcount
from students
where enroll_status = 0
and schoolid = %param1%
) cj
I am trying to return multiple counts and averages from multiple tables sorting by gender and am getting incorrect data. I understand that the following is incorrect, but I am unsure of how to fix it. (Edit: Problem with group by gender. See below.)
Here is the query:
SELECT c.gender AS 'Gender',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
(SELECT COUNT(DISTINCT CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) ) AS 'Open Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Avg Open',
(SELECT COUNT(DISTINCT CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) ) AS 'Click Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Avg Click',
COUNT(DISTINCT ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM ((mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id)
LEFT JOIN mailing_recipient_click mrc ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON c.cons_id = ca.cons_id)
WHERE m.mailing_id = 1
AND gender IS NOT NULL
GROUP BY c.gender;
Here is the table which would be correct if the totals in the fields were correct:
GENDER Mailing Recipient Open Total Avg Open Click Total Avg Click Donations Avg Amt
F 105 2 0.5000 2 0.5000 105 22.5000
M 98 2 0.5000 2 0.5000 98 18.8780
EDIT: Here is an example of what I am hoping to achieve. I am certain that the above values are being repeated. The below values are just examples of what I am expecting:
GENDER Mailing Recipient Open Total Avg Open Click Total Avg Click Donations Avg Amt
F 105 8 0.0761 4 0.0380 2 22.5000
M 98 2 0.0204 1 0.0102 1 18.8000
Edit:
After playing around a bit, I thought that I had discovered that the joining the cons table was what is giving me problematic returns, but the problem is with GROUP BY when using gender. To illustrate, this query (which is grouped by mailing name instead of gender) works beautifully.
select m.mailing_name AS 'mailing',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
SUM(CASE
when mrc.mailing_recipient_click_type_id = 2 THEN 1
END)
AS 'Open Total',
AVG(CASE
WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1
ELSE 0
END) AS 'Avg Open',
SUM(CASE
WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1
END)
AS 'Click Total',
AVG(CASE
WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1
ELSE 0
END) AS 'Avg Click',
COUNT(ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM
mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id
LEFT JOIN mailing_recipient_click mrc
ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON mr.cons_id = c.cons_id
WHERE m.mailing_id = 1
GROUP BY m.mailing_name;
The statement is identical with the exception of the first and last lines.
Try this:
I'm not sure what you mean by Avg Open and Avg Click.
SELECT c.gender AS 'Gender',
COUNT(DISTINCT mr.mailing_recipient_id) AS 'Mailing Recipients',
SUM(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Open Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 2 THEN 1 ELSE 0 END) AS 'Avg Open',
SUM(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Click Total',
AVG(CASE WHEN mrc.mailing_recipient_click_type_id = 1 THEN 1 ELSE 0 END) AS 'Avg Click',
COUNT(DISTINCT ca.cons_action_contribution_id) AS Donations,
AVG(ca.transaction_amt) AS 'Avg Donation Amt'
FROM mailing m
LEFT JOIN mailing_recipient mr ON m.mailing_id = mr.mailing_id
LEFT JOIN mailing_recipient_click mrc ON mr.mailing_recipient_id = mrc.mailing_recipient_id
LEFT JOIN cons_action_contribution ca ON mr.cons_id = ca.cons_id
LEFT JOIN cons c ON c.cons_id = ca.cons_id
WHERE m.mailing_id = 1
AND gender IS NOT NULL
GROUP BY c.gender;
I also think that mrc.mailing_recipient_click_type_id = 2 means open and mrc.mailing_recipient_click_type_id = 1 mean click seems strange to me. I would expect this data to be exclusive and stored in two different fields.
how can I achieve the desired result in mysql if my table looks like this.
result|year
1 |2011
2 |2011
1 |2011
0 |2011
1 |2012
2 |2012
1 = Won, 2 = lost, 0 = draw
Every year can have multiple values like this. Not sure how I can get the desired result like below.
year won lost draw totalPlayed
2011 2 1 1 3
2012 1 1 0 2
I have tried the following query but does not get the desired result
select year,
league_types.league_name,
sum(if(result = 1,1,0)) as won,
sum(if(result = 0,1,0)) as draw,
sum(if(result = 4,1,0)) as noResult,
sum(if(result = 2,1,0)) as lost,
sum(if(result = 3,1,0)) as tied,
sum(if(result > 0 and result < 4,1,0)) as played
from match_score_card
inner join fixtures on match_score_card.match_id = fixtures.match_id
inner join league_types on fixtures.league_id = league_types.league_id
where
team_id = 1 group by year order by year desc
Here is the SQL Fiddle that demonstrates the following query:
SELECT m.year,
SUM(CASE WHEN m.result = 1 THEN 1 ELSE 0 END) AS 'Won',
SUM(CASE WHEN m.result = 2 THEN 1 ELSE 0 END) AS 'Lost',
SUM(CASE WHEN m.result = 0 THEN 1 ELSE 0 END) AS 'Draw',
COUNT(*) AS 'TotalPlayed'
FROM MyTable AS m
GROUP BY m.year
I'm not familiar with that IF function in mySQL, but this standard SQL should work:
select year
, league_types.league_name
, sum(CASE WHEN result = 1 THEN 1 ELSE 0 END) as won
, sum(CASE WHEN result = 2 THEN 1 ELSE 0 END) as lost
, sum(CASE WHEN result = 3 THEN 1 ELSE 0 END) as draw
, sum(CASE WHEN result = 4 THEN 1 ELSE 0 END) as noResult
, sum(CASE WHEN result = 1
or result = 2 THEN 1 ELSE 0 END) as played
from match_score_card
inner join fixtures
on match_score_card.match_id = fixtures.match_id
inner join league_types
on fixtures.league_id = league_types.league_id
where team_id = 1
group by year, league_types.league_name
order by year desc, league_types.league_name
I'm guessing that you only want to count wins and losses as "played".
How to get the groupby result as column names
if staff table is there when we use
select count(*) from staff group by gender; gives me as
but i need them as columns Male | Female | None
select sum(case when gender = 'Male' then 1 else 0 end) as 'Male',
sum(case when gender = 'Female' then 1 else 0 end) as 'Female',
sum(case when gender not in ('Male','Female') or gender is null then 1 else 0 end) as 'None'
from staff;