user1256477
user1256477

Reputation: 11201

count and different results in a query

I have this query and result in my database:

mysql> SELECT id FROM jos_content 
       WHERE catid=12 AND state=1 
       AND DATE(publish_up) <= NOW() ORDER BY DATE(publish_up) DESC LIMIT 0,5;
    +----+
    | id |
    +----+
    | 48 |
    | 47 |
    | 46 |
    +----+
    3 rows in set (0.00 sec)

Now I would like to count result:

mysql> SELECT count(*), id FROM jos_content 
       WHERE catid=12 AND state=1 
       AND DATE(publish_up) <= NOW() ORDER BY DATE(publish_up) DESC LIMIT 0,5;
    +----------+----+
    | count(*) | id |
    +----------+----+
    |        3 | 46 |
    +----------+----+
    1 row in set (0.00 sec)

Why aren't the 48 and 47 results shown?

Thank you in advance

Upvotes: 2

Views: 165

Answers (2)

Michael Berkowski
Michael Berkowski

Reputation: 270677

You need to include a GROUP BY clause. By default, MySQL permits columns in the SELECT clause which are not also included in a GROUP BY (which is an error in most other RDBMS). Without the GROUP BY, MySQL will return the first of the associated columns, which is often not the correct intended result.

SELECT 
  count(*), 
  id
FROM jos_content
WHERE catid=12 AND state=1 AND DATE(publish_up) <= NOW() 
GROUP BY id
ORDER BY DATE(publish_up) DESC
LIMIT 0,5;

Not requiring all columns in the GROUP BY is helpful if you want to return multiple columns in a summary which are always unique, as something like the following, where name is unique to id, but you MUST group at least one column for an aggregate to act correctly and produce a summary:

SELECT 
  id,
  name,
  COUNT(*)
FROM tbl
GROUP BY id

For compatibility with other RDBMS, and to avoid bugs, I recommend always including all the SELECT columns in the GROUP BY explicitly.

Update

With better understanding of what you attempted, if you want the total count of all rows beside the id of each row, you can use a subselect like in the SELECT list. This is going to be a bit slow though.

SELECT
  id,
  (SELECT COUNT(*) FROM jos_content) AS numitems
FROM jos_content
WHERE catid=12 AND state=1 AND DATE(publish_up) <= NOW() 
ORDER BY DATE(publish_up) DESC
LIMIT 0,5;

You can trick this to work a little faster by doing a cartesian join (no ON clause) against the count in a subquery, so it shouldn't get executed for each row. Only do this if the subquery will return exactly one row.

SELECT
  id
  numitems
FROM 
  jos_content
  /* Join with no ON clause */
  JOIN (SELECT COUNT(*) AS numitems FROM jos_content) subq
WHERE catid=12 AND state=1 AND DATE(publish_up) <= NOW() 
ORDER BY DATE(publish_up) DESC
LIMIT 0,5;

Upvotes: 3

Romil Kumar Jain
Romil Kumar Jain

Reputation: 20765

Count is aggregate function, so if you want to include any of the column then that column must be part of group by clause in the query.

Upvotes: 0

Related Questions