Thread: Calculating Percentages

Calculating Percentages

From
David Siegal
Date:
I have 'member' table with a 'nationality' column. I want to get the
percentage breakdown of members by nationality, e.g.

American  29%
Canadian  14%
Mexican   11%
...

Is there an efficient way to do this is a single query?

If I were to do:
SELECT nationality, ((COUNT(*) * 100)/(select count(*) from member)) as
percentage FROM member GROUP BY nationality ORDER BY nationality;

would this repeatedly execute the inner query over and over?

Thanks!
David



Re: Calculating Percentages

From
Tom Lane
Date:
David Siegal <dsiegal@brave.cs.uml.edu> writes:
> If I were to do:

> SELECT nationality, ((COUNT(*) * 100)/(select count(*) from member)) as
> percentage FROM member GROUP BY nationality ORDER BY nationality;

> would this repeatedly execute the inner query over and over?

No, it'd do it just once, because the sub-select has no dependency on
the outer select.  (If the sub-select used any variables from the outer
level, then it'd have to be done over at each outer row.)

You can tell the difference between these cases by looking at EXPLAIN
output for the query: do-once sub-selects are labeled InitPlans,
do-every-time sub-selects are labeled SubPlans.
        regards, tom lane


Re: Calculating Percentages

From
Josh Berkus
Date:
David,

> If I were to do:
> SELECT nationality, ((COUNT(*) * 100)/(select count(*) from member)) as
> percentage FROM member GROUP BY nationality ORDER BY nationality;
>
> would this repeatedly execute the inner query over and over?

Yes, it would
Better is:

SELECT nationality, (COUNT(*)*100/total_members) as percentage
FROM member,(SELECT COUNT(*) as total_members FROM members) tot_mem
GROUP BY nationality
ORDER BY nationality

This method runs the grand total only once.


-- 
Josh Berkus
Aglio Database Solutions
San Francisco


Re: Calculating Percentages

From
Christoph Haller
Date:
>
> SELECT nationality, (COUNT(*)*100/total_members) as percentage
> FROM member,
>       (SELECT COUNT(*) as total_members FROM members) tot_mem
> GROUP BY nationality
> ORDER BY nationality
>
You'll have to GROUP BY nationality, total_members

Remember COUNT returns bigint, so percentage is the
result of an integer division. To obtain floating point results use
(COUNT(*)*100.0/total_members)

> > If I were to do:
>
> > SELECT nationality, ((COUNT(*) * 100)/(select count(*) from member))
as
> > percentage FROM member GROUP BY nationality ORDER BY nationality;
>
> > would this repeatedly execute the inner query over and over?
>
> No, it'd do it just once, because the sub-select has no dependency on
> the outer select.  (If the sub-select used any variables from the
outer
> level, then it'd have to be done over at each outer row.)
>
Really nice piece of analyzer.

Regards, Christoph




Re: Calculating Percentages

From
Josh Berkus
Date:
Chris, 

> You'll have to GROUP BY nationality, total_members

Oops.  Problem with posting untested SQL ...

> > > would this repeatedly execute the inner query over and over?
> >
> > No, it'd do it just once, because the sub-select has no dependency on
> > the outer select.  (If the sub-select used any variables from the

That's great, Tom.  Yet another place where we've surpassed MS SQL Server in 
query implementation.

-- 
Josh Berkus
Aglio Database Solutions
San Francisco