How to get summary totals on unique IDs using analytics? - sql

My repeating table has duplicate ids but I want summary statistics on unique ids.
Detail_id code book tree
----------- ------ ------ ------
1 BR54 COOK PINE
1 BR55 COOK PINE
1 BR51 COOK PINE
2 BR55 COOK MAPL
2 BR60 COOK MAPL
3 BR61 FORD PINE
3 BR54 FORD PINE
3 BR55 FORD PINE
Here's my query which is also on SQLFiddle
select count(case detail_book when 'COOK' THEN 1 else 0 end) as cook_total,
count(case detail_book when 'FORD' THEN 1 else 0 end) as ford_total,
count(case detail_tree when 'PINE' THEN 1 else 0 end) as pine_total,
count(case detail_book when 'MAPL' THEN 1 else 0 end) as mapl_total
from detail_records;
Desired results:
COOK_TOTAL FORD_TOTAL PINE_TOTAL MAPL_TOTL
---------- ---------- ---------- ----------
2 1 2 1

You could use analytic functions and an inline view to avoid the duplicate counting issue:
select sum(case when detail_book = 'COOK' and book_cntr = 1 then 1 else 0 end) as cook_total,
sum(case when detail_book = 'FORD' and book_cntr = 1 then 1 else 0 end) as ford_total,
sum(case when detail_tree = 'PINE' and tree_cntr = 1 then 1 else 0 end) as pine_total,
sum(case when detail_tree = 'MAPL' and tree_cntr = 1 then 1 else 0 end) as mapl_total
from (select d.*,
row_number() over(partition by detail_book, detail_id order by detail_book, detail_id) as book_cntr,
row_number() over(partition by detail_tree, detail_id order by detail_tree, detail_id) as tree_cntr
from detail_records d) v
Fiddle: http://sqlfiddle.com/#!4/889a8/31/0

I don't think you need analytic functions here:
SELECT COUNT(DISTINCT CASE WHEN detail_book = 'COOK' THEN detail_id END) AS cook_total
, COUNT(DISTINCT CASE WHEN detail_book = 'FORD' THEN detail_id END) AS ford_total
, COUNT(DISTINCT CASE WHEN detail_tree = 'PINE' THEN detail_id END) AS pine_total
, COUNT(DISTINCT CASE WHEN detail_tree = 'MAPL' THEN detail_id END) AS mapl_total
FROM detail_records;
The CASE statement returns NULL when the values don't match; those aren't counted.
Updated SQL Fiddle here. By the way, in your query you were trying to match detail_book to MAPL when I think you wanted to match detail_tree, and my query reflects that.

This answer is based on your example http://sqlfiddle.com/#!4/889a8/29 which you can use to avoid the duplicate ids by getting the distinct ids for detail_book and detail_tree
Kindly check the result here http://sqlfiddle.com/#!4/889a8/44
select sum(case detail_book
when 'COOK' THEN 1
else 0
end) as cook_total,
sum(case detail_book
when 'FORD' THEN 1
else 0
end) as ford_total,
sum(case detail_tree
when 'PINE' THEN 1
else 0
end) as pine_total,
sum(case detail_tree
when 'MAPL' THEN 1
else 0
end) as mapl_total
from
(select distinct detail_id,detail_book,detail_tree
from
detail_records);

You can modify your query to get what you want just by removing the else clause:
select count(case detail_book when 'COOK' THEN 1 end) as cook_total,
count(case detail_book when 'FORD' THEN 1 end) as ford_total,
count(case detail_tree when 'PINE' THEN 1 end) as pine_total,
count(case detail_book when 'MAPL' THEN 1 end) as mapl_total
from detail_records;
The default for case without an else is NULL, so the count() works. Personally, I prefer sum() for this type of aggregation:
select sum(case when detail_book = 'COOK' THEN 1 else 0 end) as cook_total,
sum(case when detail_book = 'FORD' THEN 1 else 0 end) as ford_total,
sum(case when detail_tree = 'PINE' THEN 1 else 0 end) as pine_total,
sum(case when detail_book = 'MAPL' THEN 1 else 0 end) as mapl_total
from detail_records;

Apart from analytical functions, I'd probably use an approach by first "flattening the table" (union all) and then pivoting the result:
select *
from (
select detail_book i
from detail_records
group by detail_id, detail_book
union all
select detail_tree
from detail_records
group by detail_id, detail_tree
)
pivot(count(i) for i in ('COOK', 'FORD', 'PINE', 'MAPL'))
;
sql fiddle

select *
from (
select decode(detail_book,'FORD','FORD_TOTAL','COOK','COOK_TOTAL','MAPL','MAPL_TOTAL','PINE','PINE_TOTAL','OTHER') i,
count(distinct detail_id) j
from detail_records
group by detail_book
union all
select DECODE(detail_tree,'FORD','FORD_TOTAL','COOK','COOK_TOTAL','MAPL','MAPL_TOTAL','PINE','PINE_TOTAL','OTHER') i,
count(distinct detail_id) j
from detail_records
group by detail_tree
)
pivot(sum(j) for i in ('COOK_TOTAL', 'FORD_TOTAL', 'PINE_TOTAL', 'MAPL_TOTAL','OTHER'))
;

Related

Combining two aggregate queries into one

For some context, I am making an image browser which is connected to an SQLite database. Within the browser, similar images are grouped into an event (EventId) and each image (MicrosoftId) is labelled with a few tags (name).
I have these two queries on the same table (TagsMSCV) but pulling out different information. Ultimately I need to combine the information in my browser so if it was possible to combine these two queries (maybe with a JOIN?) it would be a lot faster and convenient for me. Both results of these queries share the EventId column.
1st Query ():
SELECT EventId as 'event', count(*) as 'size',
SUM(case when tag_count = 1 then 1 else 0 end) as '1',
SUM(case when tag_count = 2 then 1 else 0 end) as '2',
SUM(case when tag_count = 3 then 1 else 0 end) as '3'
FROM (SELECT EventId, MicrosoftId,
SUM(case when name in ('indoor', 'cluttered', 'screen') then 1 else 0 end) as tag_count
FROM TagsMSCV GROUP BY EventId, MicrosoftId) TagsMSCV
GROUP BY EventId ORDER BY 3 DESC, 2 DESC, 1 DESC
2nd Query
SELECT EventId,
SUM(CASE WHEN name = 'indoor' THEN 1 ELSE 0 END) as indoor,
SUM(CASE WHEN name = 'cluttered' THEN 1 ELSE 0 END) as cluttered,
SUM(CASE WHEN name = 'screen' THEN 1 ELSE 0 END) as screen
FROM TagsMSCV WHERE name IN ('indoor', 'cluttered', 'screen')
GROUP BY EventId
As you can see in both queries I am feeding in the tags 'necktie' 'man', 'male' and getting different information back.
SQL Fiddle Here: https://www.db-fiddle.com/f/f8WNimjmZAj1XXeCj4PHB8/3
You should do this all in one query:
SELECT EventId as event, count(*) as size,
SUM(case when (indoor + cluttered + screen) = 1 then 1 else 0 end) as tc_1,
SUM(case when (indoor + cluttered + screen) = 2 then 1 else 0 end) as tc_2,
SUM(case when (indoor + cluttered + screen) = 3 then 1 else 0 end) as tc_3,
SUM(indoor) as indoor,
SUM(cluttered) as cluttered,
SUM(screen) as screen
FROM (SELECT EventId, MicrosoftId,
SUM(CASE WHEN name = 'indoor' THEN 1 ELSE 0 END) as indoor,
SUM(CASE WHEN name = 'cluttered' THEN 1 ELSE 0 END) as cluttered,
SUM(CASE WHEN name = 'screen' THEN 1 ELSE 0 END) as screen
FROM TagsMSCV
GROUP BY EventId, MicrosoftId
) TagsMSCV
GROUP BY EventId
ORDER BY 3 DESC, 2 DESC, 1 DESC;
You need two aggregations to get the information about the tag counts. There is no need to add more aggregations and joins to the query.
You could use an Inner join subquery
SELECT TagsMSCV.EventId as 'event', count(*) as 'size',
SUM(case when tag_count = 1 then 1 else 0 end) as '1',
SUM(case when tag_count = 2 then 1 else 0 end) as '2',
SUM(case when tag_count = 3 then 1 else 0 end) as '3',
t.necktie,
t.man,
t.male
FROM (
SELECT EventId, MicrosoftId,
SUM(case when name in ('necktie' 'man', 'male') then 1 else 0 end) as tag_count
FROM TagsMSCV GROUP BY EventId, MicrosoftId
) TagsMSCV
INNER JOIN (
SELECT EventId,
SUM(CASE WHEN name = 'necktie' THEN 1 ELSE 0 END) as necktie,
SUM(CASE WHEN name = 'man' THEN 1 ELSE 0 END) as man,
SUM(CASE WHEN name = 'male' THEN 1 ELSE 0 END) as male
FROM TagsMSCV WHERE name IN ('necktie' 'man', 'male')
GROUP BY EventId
) t on t.EventId = TagsMSCV.EventId
GROUP BY TagsMSCV.EventId
ORDER BY 3 DESC, 2 DESC, 1 DESC

Exclude records that have sum greater than 1

I have query returning details of customers that are subscribed to channel xyz or all other channels.
To generate this results i am using the following query:
select customerID
,sum(case when channel='xyz' then 1 else 0 end) as 'xyz Count'
,sum(case when channel<>'xyz' then bundle_qty else 0 end) as 'Other'
From temptable
So my Question is, how do i Exclude customers that are subscribed to 2 channels, where one is xyz and one is another channel.
select customerID
,sum(case when channel='xyz' then 1 else 0 end) as 'xyz Count'
,sum(case when channel<>'xyz' then bundle_qty else 0 end) as 'Other'
From temptable
group by customerID
having sum(case when channel= 'xyz' then 1 else 0 end) > 0
and sum(case when channel<>'xyz' then 1 else 0 end) > 0
First, your query is not correct. It needs a group by. Second, you can do what you want using having:
select customerID,
sum(case when channel = 'xyz' then 1 else 0 end) as xyz_Count,
sum(case when channel<>'xyz' then bundle_qty else 0 end) as Other
From temptable
group by customerID
having count(*) = 2 and
sum(case when channel = 'xyz' then 1 else 0 end) = 1;
If customers can subscribe to the same channel multiple times, and you still want only "xyz" and another channel, then:
having count(distinct channel) = 2 and
(min(channel) = 'xyz' or max(channel) = 'xyz')

Combinations of Products as single count

I need to count combinations of products within transactions differently to other products and I'm struggling with how to do this within a single select statement from SQL 2008. This would then become a data set to manipulate in Reporting Services
raw data looks like this
txn, prod, units
1, a, 2
1, c, 1
2, a, 1
2, b, 1
2, c, 1
3, a, 2
3, b, 1
4, a, 3
4, c, 2
So a+b should = one if in same trans number, however a or b should equal one if not paired. So a=1 and b=1 but a+b=1, a+b+a=2, a+b+a+b=2 given the example data here is my desired result with an explanation of why
txn 1 is 3 units -- 2a + c
txn 2 is 2 units -- (a+b) + c
txn 3 is 2 units -- (a+b) + a
txn 4 is 5 units -- 3a + 2c
My query is more complex than this and includes other aggregates so I would like to group by transaction which I can't do as I need to manipulate at a lower grain
Update Progress :
Possible solution, I've generated columns based on the products I'm measuring. This allows me to group on Txn as I am now aggregating that field. Unsure if there's a better way to do it as it does take a little while
CASE WHEN SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end)=0
THEN SUM(CASE WHEN Prod='a' then 1 else 0 end)
ELSE 0 END AS MixProd
, CASE WHEN SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end)!=0
THEN ABS(SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end))
ELSE 0 END AS NotMixProd
I will then need to sort out the current unit aggregate to remove the extras but this certainly gives me a start
Update Progress 2 :
This failed to handle 0 correctly where a or b was 0 it would still give a value for mix because a-b was not zero. I reverted to an earlier draft that I lost and expanded as per below
, CASE WHEN SUM(CASE WHEN Prod='a' then 1 else 0 end) = 0 THEN 0
WHEN SUM(CASE WHEN Prod='b' then 1 else 0 end) = 0 THEN 0
WHEN SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end)=0
THEN SUM(CASE WHEN Prod='a' then 1 else 0 end)
ELSE ABS(SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end))
END AS MixProd
, CASE WHEN SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end)!=0
THEN ABS(SUM(CASE WHEN Prod='a' then 1 else 0 end)-
SUM(CASE WHEN Prod='b' then 1 else 0 end))
ELSE 0 END AS NotMixProd
UPDATE: This should work in SQL Server 2008 (based on LAG solution from here).
Here is the demo: http://rextester.com/GNI23706
WITH CTE AS
(
select txn, prod, units,
row_number() over (partition by txn order by prod) rn,
(row_number() over (partition by txn order by prod))/2 rndiv2,
(row_number() over (partition by txn order by prod)+1)/2 rnplus1div2,
count(*) over (partition by txn) partitioncount
from test_data
)
select
txn,
sum(case when prev_prod = 'a' and prod = 'b' and prev_units >= units then 0
when prev_prod = 'a' and prod = 'b' and prev_units < units then units - prev_units
else units
end) units
from
(
select
txn,
prod,
units,
CASE WHEN rn%2=1
THEN MAX(CASE WHEN rn%2=0 THEN prod END) OVER (PARTITION BY txn,rndiv2)
ELSE MAX(CASE WHEN rn%2=1 THEN prod END) OVER (PARTITION BY txn,rnplus1div2)
END AS prev_prod,
CASE WHEN rn%2=1
THEN MAX(CASE WHEN rn%2=0 THEN units END) OVER (PARTITION BY txn,rndiv2)
ELSE MAX(CASE WHEN rn%2=1 THEN units END) OVER (PARTITION BY txn,rnplus1div2)
END AS prev_units
from cte
) temp
group by txn
For SQL Server 2012+, use LAG:
select
txn,
sum(
case when prev_prod = 'a' and prod = 'b' and prev_units >= units then 0
when prev_prod = 'a' and prod = 'b' and prev_units < units then units - prev_units
else units
end) units
from
(
select
txn,
prod,
units,
lag(prod) over (partition by txn order by prod) prev_prod,
lag(units) over (partition by txn order by prod) prev_units
from test_data
) temp
group by txn
I decided in the end that a temp table was the best way to go, because I couldn't group on a collation. So I eventually tweaked the code above as it was failing to pick up the spare items correctly
SUM(Units) AS OldUnits
SUM(Units) -
(CASE WHEN
SUM(CASE WHEN Prod='a' THEN 1 ELSE 0 END) = 0 THEN 0 WHEN
SUM(CASE WHEN Prod='b' THEN 1 ELSE 0 END) = 0 THEN 0 WHEN
SUM(CASE WHEN Prod='a' THEN 1 ELSE 0 END) -
SUM(CASE WHEN Prod='b' THEN 1 ELSE 0 END) = 0 THEN
SUM(CASE WHEN Prod='a' THEN 1 ELSE 0 END) WHEN
(SUM(CASE WHEN Prod='a' THEN 1 ELSE 0 END) -
SUM(CASE WHEN Prod='b' THEN 1 ELSE 0 END)) < 0 THEN
SUM(CASE WHEN Prod='a' THEN 1 ELSE 0 END) ELSE
SUM(CASE WHEN Prod='b' THEN 1 ELSE 0 END) END) AS NewUnits
This was stored in a temptable that I could then collate on Trans as the next step. Works fine for my purposes and helped me overcome a mild irrational fear I have of temptables

How to select on table and count occurrences some values

I am asking you for a help because I do not know SQL very well.
I need to count occurrences some values from table column to achieve effect like statistics table which will look like at the picture below:
Needed result:
Comment:
My Result Table needs to have first two columns (contry and site) comes from first table "Violations" and next 5 columns which will contain numbers (count) of occurrences status_id in "Violations" in each of possible values of id from Status table.
Explanation:
So, I have existing two tables: Violations and Status. Please look at my sqlfiddle
Violations:
id long,
country varchar(20),
site varchar(20),
status_id long, <-- this is the id of status in Status table.
... other columns not important in this case
Status:
id long,
status long
Column "status" have values (1-4) which are mapped to string values: Suspected Violation (1), Confirmed Violation (2), Confirmed No Violation (3), Not Determined (4)
In result of my join (or based only on one table Violations) is to have table which should contain columns:
from Violations table: "Country" and "Site"
from Status table: "Suspected Violation", "Confirmed Violation", "Confirmed No Violation", "Not Determined", "Total" (where this columns are counters of occurrences in Violation table).
Current Status and new Requirements:
First try is done (thanks to bluefeet) below and is almost perfect...
select v.country,
v.site,
SUM(case when s.id = 1 then 1 else 0 end) Total_SuspectedViolations,
SUM(case when s.id = 2 then 1 else 0 end) Total_ConfirmedViolations,
SUM(case when s.id = 3 then 1 else 0 end) Total_ConfirmedNoViolations,
SUM(case when s.id = 4 then 1 else 0 end) Total_NotDetermined,
COUNT(*) Total
from violations v
inner join status s
on v.status_id = s.id
group by v.country, v.site
or without JOIN:
select v.country,
v.site,
SUM(case when v.status_id = 1 then 1 else 0 end) Total_SuspectedViolations,
SUM(case when v.status_id = 2 then 1 else 0 end) Total_ConfirmedViolations,
SUM(case when v.status_id = 3 then 1 else 0 end) Total_ConfirmedNoViolations,
SUM(case when v.status_id = 4 then 1 else 0 end) Total_NotDetermined,
COUNT(*) Total
from violations v
group by v.country, v.site
...but is not including 3 issues as you can see in the picture which should be. I mean:
"- All -" which should count occurrences for all countries
"- Unknown -" which should count occurrences for some not recognized countries
"- All -" (regarding to each country) - which should count occurrences within one country
Additional Explanation:
-Unknown- meaning:
Unknown should count occurrences for countries which for example do not exists in DB Country table or have a wrong name/id and that's why is treated here as Unknown (I forgot mention that there is table Country in DB).
The same for sites, Unknown for sites means that someone put wrong value in Violations.status_id not from range (1-4) because these are only acceptable values existing in Status table.
We can assume that table Country looks like:
Country:
id long,
name varchar(30)
Please help me to write correct sql query which would include these 3 conditions, because I have a big problem to do that.
The All case can be easily done using UNION statement (see sqlFiddle for results):
(SELECT v.country,
v.site,
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
0 'isAll'
FROM violations v
GROUP BY v.country, v.site)
union(
SELECT v.country,
'- All -',
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
1 'isAll'
FROM violations v
GROUP BY v.country)
UNION (
SELECT '- All -',
'- All -',
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
1 'isAll'
FROM violations v)
ORDER BY country, isAll DESC, site
However, the performance may not be really great with that kind of query, so I'm not saying it's the best possible solution - but it works.
Version with 'Unknow'
http://www.sqlfiddle.com/#!2/abfb7/21
(SELECT IF(c.name IS NULL, '- Unknow -', c.name) as name,
v.site,
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
0 'isAll'
FROM violations v LEFT JOIN country c ON c.name = v.country
GROUP BY c.name, v.site)
union(
SELECT IF(c.name IS NULL, '- Unknow -', c.name) as name,
'- All -',
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
1 'isAll'
FROM violations v LEFT JOIN country c ON c.name = v.country
GROUP BY c.name)
UNION (
SELECT '- All -',
'- All -',
SUM(CASE WHEN v.status_id = 1 THEN 1 ELSE 0 END) Total_SuspectedViolations,
SUM(CASE WHEN v.status_id = 2 THEN 1 ELSE 0 END) Total_ConfirmedViolations,
SUM(CASE WHEN v.status_id = 3 THEN 1 ELSE 0 END) Total_ConfirmedNoViolations,
SUM(CASE WHEN v.status_id = 4 THEN 1 ELSE 0 END) Total_NotDetermined,
COUNT(*) Total,
1 'isAll'
FROM violations v LEFT JOIN country c ON c.name = v.country)
ORDER BY name, isAll DESC, site
Using with rollup you will get the needed sum field which you want
select v.country,
v.site,
SUM(case when s.id = 1 then 1 else 0 end) Total_SuspectedViolations,
SUM(case when s.id = 2 then 1 else 0 end) Total_ConfirmedViolations,
SUM(case when s.id = 3 then 1 else 0 end) Total_ConfirmedNoViolations,
SUM(case when s.id = 4 then 1 else 0 end) Total_NotDetermined,
COUNT(*) Total
from violations v
inner join status s
on v.status_id = s.id
group by v.country, v.site WITH ROLLUP
Hope this helps
REFER for with rollup documentation
FIDDLE

DB query: How to count maximum for several columns

Assume I have the following table
claim_date person_type
------------------------
01-01-2012 adult
05-05-2012 adult
12-12-2012 adult
12-12-2012 adult
05-05-2012 child
05-05-2012 child
12-12-2012 child
When I execute the following query:
select
claim_date,
sum(case when person_type = 'adult' then 1 else 0 end) as "nbr_of_adults",
sum(case when person_type = 'child' then 1 else 0 end) as "nbr_of_children"
from my_table
group by claim_date
;
I get this result here:
claim_date nbr_of_adults nbr_of_children
---------------------------------------------
01-01-2012 1 0
05-05-2012 1 2
12-12-2012 2 1
What I would like to receive is the maximum number of adults (here: 2) and the maximum number of children (here: 2).
Is there a way to achieve this with a single query? Thanks for any hints.
Use derived table to get counts, and then select max:
select max(nbr_of_adults) max_adults,
max(nbr_of_children) max_children
from
(
select
sum(case when person_type = 'adult' then 1 else 0 end) as "nbr_of_adults",
sum(case when person_type = 'child' then 1 else 0 end) as "nbr_of_children"
from my_table
group by claim_date
) a
With nested query :
select max(nbr_of_adults) maxAd, max(nbr_of_children), maxCh from
(
select
claim_date,
sum(case when person_type = 'adult' then 1 else 0 end) as "nbr_of_adults",
sum(case when person_type = 'child' then 1 else 0 end) as "nbr_of_children"
from my_table
group by claim_date
)
I don't know what is your dbms, but on sybase it works:
select
max(sum(case when person_type = 'adult' then 1 else 0 end)) as "nbr_of_adults",
max(sum(case when person_type = 'child' then 1 else 0 end)) as "nbr_of_children"
from my_table
group by claim_date
select
person_type,
sum(case when person_type = 'adult' then 1 else 0 end) as "nbr_of_adults",
sum(case when person_type = 'child' then 1 else 0 end) as "nbr_of_children"
from my_table
group by claim_date ;
If your SQL product supports window aggregate functions, you could try something like this:
SELECT DISTINCT
MAX(COUNT(CASE person_type WHEN 'adult' THEN 1 END)) OVER () AS max_adult_count,
MAX(COUNT(CASE person_type WHEN 'child' THEN 1 END)) OVER () AS max_child_count
FROM claim_table
GROUP BY claim_date
I also replaced your conditional SUM with a conditional COUNT, which seemed to me both clearer and more succinct.