Counting two different values for each year - sql

I have a table which includes Years and Genders. Here is an example of my table:
YEAR Sex
1999 M
1999 M
1999 F
1999 F
I use this query for taking my result.
SELECT YEAR,COUNT(*)
FROM athlete_events
WHERE SEX = 'M'
GROUP BY YEAR;
And I see this result on output:
YEAR COUNT(*)
1999 2
However I want to see this result:
YEAR COUNT_MALE COUNT_FEMALE
1999 2 2
Is that possible in Pracle SQL?

You can do conditional aggregation with a case expression:
select year,
count(case when sex = 'M' then year end) as count_male,
count(case when sex = 'F' then year end) as count_female
from athlete_events
group by year;
YEAR COUNT_MALE COUNT_FEMALE
---------- ---------- ------------
1999 2 2
The count function ignores nulls, so rows that don't match the specified flag (which default to null in the case expression; you can have an explicit else null if you prefer) are not counted.
(Personally I prefer to use count() rather than sum() for this sort of thing as that better reflects what you're actually doing - counting things.)

You need conditional aggregation :
select year,
sum(case when SEX = 'M' then 1 else 0 end) as count_male,
sum(case when SEX = 'F' then 1 else 0 end) as count_female
from athlete_events
group by year;

You can do subqueries, something like this:
SELECT
E.YEAR,
(select count(*) from athlete_events M where M.YEAR=E.YEAR and M.SEX='M') COUNT_MALE,
(select count(*) from athlete_events F where F.YEAR=E.YEAR and F.SEX='F') COUNT_FEMALE
FROM athlete_events E
GROUP BY E.YEAR;
This is more expensive (performance-wise) than conditional aggregation, on the other hand maybe easier to understand and maintain.

Related

SQL query to get count of distinct values of columns in a same table

I have table with columns like Gender, Status.
The table value is something like this
ID
Gender
Status
1
Male
A01
2
Male
3
Female
A02
4
Female
5
Unknown
6
Male
7
Female
8
Unknown
I want to display
Gender
Status
Count
Male
A01
1
Female
A02
1
Unknown
0
I tried
SELECT
t3.Gender, t3.Status, COUNT(*) AS count
FROM
(SELECT DISTINCT
t1.Gender, t1.Status
FROM
Consumer AS t1
CROSS JOIN
Consumer AS t2
WHERE
t1.Status <> t2.Status
OR t1.Status <> t2.Status) AS t3
GROUP BY
t3.Gender, t3.Status
The final output something I want to display is
Please help on this. Thanks
Since the desired results have now been updated, the solution is now much different.
Try:
SELECT
CASE WHEN GROUPING(Status) = 1 THEN 'Total' ELSE Status END AS Status,
--ISNULL(Status, 'Total') AS Status, -- This would not work is actual Status might be null
COUNT(CASE WHEN Gender = 'Female' THEN 1 END) AS Female,
COUNT(CASE WHEN Gender = 'Male' THEN 1 END) AS Male,
COUNT(CASE WHEN Gender = 'Unknown' THEN 1 END) AS Unknown,
COUNT(*) AS Count
FROM #Consumer
WHERE Status > ''
GROUP BY Status WITH Rollup
ORDER BY GROUPING(Status), Status
The above uses conditional aggregation to get the partial counts. WITH ROLLUP automatically creates a totals row. The ISNULL() sets a status label for that row (which would otherwise display as null). lastly, the GROUPING() in the ORDER BY places the rollup/total after the detail rows.
See this db<>fiddle or this one with expanded test data.
There are also ways to do this using a pivot table, but the above may be sufficient for your current needs.
select *
,Male + Female + Unknown as count
from t
pivot(count(id) for gender in(Male, Female, Unknown))p
where status is not null
union all
select 'Total'
,count(case when gender = 'Male' then status end) as Male
,count(case when gender = 'Female' then status end) as Female
,count(case when gender = 'Unknown' then status end) as Unknown
,count(status) as Total
from t
Status
Male
Female
Unknown
count
A01
1
0
0
1
A02
0
1
0
1
Total
1
1
0
2
Fiddle
You might be overthinking your requirements. Perhaps the following will work:
SELECT Gender, Status, COUNT(*) AS count
FROM Consumer
GROUP BY Gender, Status
ORDER BY Gender, Status
It was not clear what you were expecting in your results for unknown gender. If you need special handling for unknown gender and/or blank status, you can add a WHERE condition to the above for the normal cases and the UNION ALL the results with a second query to handle the special cases.
SELECT Gender, Status, COUNT(*) AS count
FROM Consumer
WHERE Gender <> 'Unknown' AND Status > ''
GROUP BY Gender, Status
UNION ALL
SELECT 'Unknown' AS Gender, '' AS Status, COUNT(*) AS count
FROM Consumer
WHERE NOT (Gender <> 'Unknown' AND Status > '')

2 column with 2 different condition in one table

is it possible to create a query that will output 2 column with 2 different WHERE clause
this my ideal output:
| YEAR | WW | COUNT | *COUNT2 |
where count 1 is the result of the 1st WHERE clause. Which I already created.
What I want is to have another column where in the value will be with different WHERE clause.
here's my query:
SELECT extract(YEAR FROM EVT_TARGET) as Years, to_char(EVT_TARGET, 'ww') AS WorkWeek, COUNT(*)
FROM r5events
WHERE EVT_JOBTYPE = 'CORR' AND EVT_RSTATUS <> 'C' AND EVT_TARGET IS NOT NULL
GROUP BY extract(YEAR FROM EVT_TARGET), to_char(EVT_TARGET, 'ww');
with this query I was able to get the 1st 3 column, my problem now is how to supply value on the 4th column with the value of EVT_RSTATUS = 'C'.
Any insight?
TIA
I think you want conditional aggregation:
SELECT
extract(YEAR FROM EVT_TARGET) as Years,
to_char(EVT_TARGET,'ww') AS WorkWeek,
SUM(CASE WHEN EVT_RSTATUS <> 'C' THEN 1 ELSE 0 END) AS cnt1,
SUM(CASE WHEN EVT_RSTATUS = 'C' THEN 1 ELSE 0 END) AS cnt2
FROM r5events
WHERE EVT_JOBTYPE ='CORR' AND EVT_TARGET IS NOT NULL
GROUP BY extract(YEAR FROM EVT_TARGET), to_char(EVT_TARGET,'ww');

How to aggregate functions with groupby in SQL

I have tables like this.
I would like to groupbyand aggregate this in diffrent aggregate functions.
product sex age
A M 10
B F 20
A F 30
C M 40
my desired result is like below.
Now I can group in productkey, but in this case, I must group them byproductandsex.
Are there any way to achieve it?
count(M) count(F) avarage(M) average(F)
A 1 1 10 30
B 0 1 NA 20
C 1 0 40 NA
Thanks
With conditional aggregation:
select product,
sum(case when sex = 'M' then 1 else 0 end),
sum(case when sex = 'F' then 1 else 0 end),
avg(case when sex = 'M' then age end),
avg(case when sex = 'F' then age end)
from tablename
group by product
You can simply use the PIVOT as follows:
select * from your_Table
pivot
(count(1) as cnt, avg(age) as average for sex in ('M','F'))

SQL get count from one table and split to two columns

I have a table like this:
Date Product
1/1/2015 Apples
1/1/2015 Apples
1/1/2015 Oranges
1/2/2015 Apples
1/2/2015 Apples
1/2/2015 Oranges
How can I do a select so I get something like this:
Date Count of Apples Count of Oranges
1/1/2015 2 1
1/2/2015 2 1
Thanks. I have tried case like this but the error is being thrown:
Select 'Date',
CASE WHEN 'Product' = 'Apples' THEN COUNT(*) ELSE 0 END as 'Count'
FROM #TEMP Group by 1,2
Each GROUP BY expression must contain at least one column that is not an outer reference.
You can do conditional aggregation like this:
select
[date],
sum(case when Product = 'Apples' then 1 else 0 end) as [Count of Apples],
sum(case when Product = 'Oranges' then 1 else 0 end) as [Count of Oranges]
from #temp
group by [date]
With conditional aggregation:
select date,
sum(case when Product = 'Apples' then 1 else 0 end) as Apples,
sum(case when Product = 'Oranges' then 1 else 0 end) as Oranges,
from table
group by date
SQL Server does not accept column references in the GROUP BY. So, "1" and "2" refer to, well, the numbers one and two.
However, you seem to be confusing string constants and columns. Only use single quotes for string and date constants. I suspect that Date and Product are the names of columns. So, the query you probably want is a conditional aggregation:
Select Date,
SUM(CASE WHEN Product = 'Apples' THEN 1 ELSE 0 END) as NumApples
FROM #TEMP
Group by Date
Order by Date;

Using distinct and case for two separate columns

I am counting cases by year using the following code:
COUNT(CASE WHEN Year(FilingDate)=2008 THEN 1 ELSE NULL END) AS '2008'
and I want to only count these cases when another column is distinct. The other column is called 'FilingDate' What I imagine would look something like this:
COUNT(CASE distinct (DocketNumber) WHEN Year(FilingDate)=2008 THEN 1 ELSE NULL END) AS '2008',
The Sample Records:
DocketNumber FilingDate
123 2008
123 2008
123 2008
111 2009
112 2009
I would just like to recieve = 1
Any Ideas?
Thanks
Use option with SUBQUERY and GROUP BY clause
SELECT COUNT(CASE WHEN YearFilingDate = 2008 THEN 1 END) AS '2008'
FROM
(
SELECT Year(FilingDate) AS YearFilingDate, DocketNumber
FROM dbo.test55
GROUP BY Year(FilingDate), DocketNumber
) x
Demo on SQLFiddle
SELECT COUNT(CASE WHEN Year(FilingDate)=2008 THEN 1 ELSE NULL END) AS '2008'
GROUP BY DocketNumber
may be.