12

I want to count both the total # of records in a table, and the total # of records that match certain conditions. I can do these with two separate queries:

SELECT COUNT(*) AS TotalCount FROM MyTable;
SELECT COUNT(*) AS QualifiedCount FROM MyTable
  {possible JOIN(s) as well e.g. JOIN MyOtherTable mot ON MyTable.id=mot.id} 
  WHERE {conditions};

Is there a way to combine these into one query so that I get two fields in one row?

SELECT {something} AS TotalCount, 
  {something else} AS QualifiedCount 
  FROM MyTable {possible JOIN(s)} WHERE {some conditions}

If not, I can issue two queries and wrap them in a transaction so they are consistent, but I was hoping to do it with one.

edit: I'm most concerned about atomicity; if there are two sub-SELECT statements needed that's OK as long as if there's an INSERT coming from somewhere it doesn't make the two responses inconsistent.

edit 2: The CASE answers are helpful but in my specific instance, the conditions may include a JOIN with another table (forgot to mention that in my original post, sorry) so I'm guessing that approach won't work.

3
  • What kind of database are you using? Commented May 20, 2009 at 15:48
  • MySQL but I would like to know it in general if it's pretty straightforward Commented May 20, 2009 at 15:54
  • Related but not to the solution: you can also use to get the counts for larger tables. SELECT SQL_CALC_FOUND_ROWSFROM MyTable; SELECT FOUND_ROWS(); SELECT SQL_CALC_FOUND_ROWSFROM MyTable WHERE {conditions}; SELECT FOUND_ROWS(); Commented May 20, 2009 at 16:03

5 Answers 5

26

One way is to join the table against itself:

select
   count(*) as TotalCount,
   count(s.id) as QualifiedCount
from
   MyTable a
left join
   MyTable s on s.id = a.id and {some conditions}

Another way is to use subqueries:

select
   (select count(*) from Mytable) as TotalCount,
   (select count(*) from Mytable where {some conditions}) as QualifiedCount

Or you can put the conditions in a case:

select
   count(*) as TotalCount,
   sum(case when {some conditions} then 1 else 0 end) as QualifiedCount
from
   MyTable

Related:

SQL Combining several SELECT results

Sign up to request clarification or add additional context in comments.

1 Comment

The self-join handles the case where there are other joins in the conditions.
21

In Sql Server or MySQL, you can do that with a CASE statement:

select 
    count(*) as TotalCount,
    sum(case when {conditions} then 1 else 0 end) as QualifiedCount
from MyTable

Edit: This also works if you use a JOIN in the condition:

select 
    count(*) as TotalCount,
    sum(case when {conditions} then 1 else 0 end) as QualifiedCount
from MyTable t
left join MyChair c on c.TableId = t.Id
group by t.id, t.[othercolums]

The GROUP BY is there to ensure you only find one row from the main table.

7 Comments

Just want to point out that this example will perform much better than any union or join as it only has to evaluate the table in question once
I like this technique, it's elegant.
is that syntax "Alias = Expression" particular to SqlServer/MySQL or is it fairly general?
It's pretty SqlServer specific, I'll change it
I wouldn't have thought of using Sum() like this. +1
|
7

if you are just counting rows you could just use nested queries.

select 
    (SELECT COUNT(*) AS TotalCount FROM MyTable) as a,
    (SELECT COUNT(*) AS QualifiedCount FROM MyTable WHERE {conditions}) as b

2 Comments

I agree this is the better way to get the result as it gets you want and should give it to you in about the same time as the separate executions.
This query will get you the answer, but the cost of two select statements and the where clause make the CASE solution more efficient
1

In Oracle SQL Developer I had to add a * FROM in my select, or else i was getting a syntax error:

select * FROM 
    (select COUNT(*) as foo FROM TABLE1),
    (select COUNT(*) as boo FROM TABLE2);

Comments

0

MySQL doesn't count NULLs, so this should work too:

SELECT count(*) AS TotalCount, 
  count( if( field = value, field, null)) AS QualifiedCount 
  FROM MyTable {possible JOIN(s)} WHERE {some conditions}

That works well if the QuailifiedCount field comes from a LEFT JOIN, and you only care if it exists. To get the number of users, and the number of users that have filled in their address:

SELECT count( user.id) as NumUsers, count( address.id) as NumAddresses
  FROM Users
  LEFT JOIN Address on User.address_id = Address.id;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.