tags:

views:

106

answers:

2

Each item in c_data is in a category/section. I would like to limit how many items are displayed per category, rather than limiting the total number of items retrieved. Obviously if I add something like "limit 20" to the query, it will only fetch 20 results in total, rather than 20 results per category.

   SELECT cm.id,
                cm.title AS cmtitle,
                cm.sectionid,
                cm.type AS cmtype,
                cd.id,
                cd.time,
                cd.link,
                cd.title,
                cd.description,
                cd.sectionid AS sectionid
      FROM c_main AS cm
      JOIN c_data AS cd ON cd.sectionid=cm.sectionid
     WHERE cd.sectionid=cm.sectionid 
     ORDER by id ASC

The field with the category is "sectionid".

+3  A: 

The answers to this previous post should help you to solve that problem.

EDIT:

It should work with using row numbers.

I have not tried it, but this should work:

set @section = '';
set @num  = 1;

SELECT y.*
FROM
(
    SELECT
      x.*, 
      @num := if(@section = sectionid, @num + 1, 1) as row_number,
      @section := sectionid
    FROM
    (
        SELECT 
          cm.id AS cm_id,
          cm.title AS cmtitle,
          cm.sectionid,
          cm.type AS cmtype,
          cd.id AS cd_id,
          cd.time,
          cd.link,
          cd.title,
          cd.description
        FROM c_main AS cm
        JOIN c_data AS cd ON ( cd.sectionid=cm.sectionid )
        ORDER by cd.sectionid ASC, cm.id ASC
    ) x
) y
WHERE y.row_number <= 20;
Peter Lang
The initial intention of the question was to take the last 15 rows, not days. astander's answer points to using rownumbers. I'm going to provide a better answer though, unless you beat me ;-)
Peter Lang
@OMG Ponies: Thanks, I corrected that.
Peter Lang
+1: It was your algorithm after all, I was just quicker at implementing it.
OMG Ponies
This throws up a syntax error right away, so I'm not able to test it.
@nsan: I added some aliases, so could you please try the code again? If it still does not work, could you please post the error you get?
Peter Lang
"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'set @num = 1; SELECT y.* FROM ( SELECT x.*, @num := if' at line 2"
As you seem to have a problem with pre-initializing the variables, I'd suggest to use the solution provided by OMG Ponies. I tried both of our versions, and they return the same (in my opinion correct) result.
Peter Lang
+2  A: 

MySQL doesn't have any ranking functionality, but you can use a variable to create a psuedo row number.

Use:

SELECT x.*
  FROM (SELECT cm.id,
               cm.title AS cmtitle,
               cm.sectionid,
               cm.type AS cmtype,
               cd.id AS cd_id,
               cd.time,
               cd.link,
               cd.title,
               cd.description,
               cd.sectionid AS cd_sectionid,
               CASE
                 WHEN @sectionid != cm.sectionid THEN @rownum := 1 
                 ELSE @rownum := @rownum + 1
               END AS rank,
               @sectionid := cm.sectionid
          FROM C_MAIN cm,
               C_DATA cd,
               (SELECT @rownum := 0, @sectionid := NULL) r
         WHERE cm.sectionid = cd.sectionid
      ORDER BY cm.sectionid) x
 WHERE x.rank <= 20
ORDER BY id
OMG Ponies
I think you are missing a `,` after `END AS rank`. Would your solution work if sectionid's are not sorted?
Peter Lang
A syntax error is given with this, even after adding a comma after END AS rank.
It was missing two commas - `cd.sectionid AS sectionid,`, and after `AS rank`
OMG Ponies
@Peter: True about sorting by sectionid to ensure that the numbering is correct. Because it will only increment when they are different, there's a change that a lot of them would have a rank of 1/etc.
OMG Ponies
I'm now receiving this error: Duplicate column name 'id'
@nsan: I added column aliases, because you have `cm.id` and `cd.id`. Otherwise, it's not obvious where you could get a duplicate id error unless you aren't using the table aliases as provided in my answer.
OMG Ponies
Working now. The issue now is that it doesn't limit the results correctly. Some of the categories will show over 40 results unless I lower the limit, which also further lowers the others.
I tried this solution, and it just works fine. It returns 20 rows for `test3` (as this sectionid has more than 20 rows), and all rows for the other sectionids in your provided test-data.
Peter Lang
I should have looked at the obvious, which is the php code being used to display said results. The mysql statement works fine otherwise.