tags:

views:

109

answers:

4

Let's say there are two tables:

Table "photos" with columns:

id,
title,
path,
user_id

And table "users" with columns:

id
username

What I want to do is select let's say 30 photos from the "photos" table but with condition that there are at most 3 photos from the same user in the fetched result set. So far I have this query:

SELECT p.*, u.username FROM photos AS p 
INNER JOIN users AS u ON u.id = p.user_id 
ORDER BY p.id DESC LIMIT 30;

How to create a WHERE clause to achieve max. 3 rows from the same user in the fetched result set?

EDIT: I'm using MySQL 5.1.33

+4  A: 
SELECT p.*, u.username 
FROM photos AS p 
INNER JOIN users AS u ON u.id = p.user_id 
WHERE p.id in (
 SELECT id  
 FROM photos p
 WHERE user_id  = p.user_id 
 LIMIT 3
)
ORDER BY p.id DESC LIMIT 30;
RedFilter
No TOP in MySQL :( Try again.
Asaph
Would that work in MySQL? I tried the query in phpmyadmin and I got an error, I think "top" is not supported by MySQL.
Richard Knop
Replaced TOP with LIMIT.
RedFilter
Still doesn't work. I'm using MySQL 5.1.33 and it doesn't support LIMIT clause in SELECT subqueries.
Richard Knop
+1  A: 

Hand translated from T-SQL, so untested on MySQL.

SELECT p.*, u.username
FROM photos AS p
INNER JOIN users AS u ON u.id = p.user_id
WHERE p.id IN (
 SELECT p1.id
 FROM photos p1
 JOIN photos p2
 ON p1.user_id = IFNULL( p2.user_id, p1.user_id )
 AND p1.id <= IFNULL( p2.id, p1.id )
 GROUP BY p1.id
 HAVING COUNT(*) < 4
)
LIMIT 30
martin clayton
This returns an empty result set (and there are rows in the table that fulfill the condition).
Richard Knop
Worked for me on 5.0.41. What data type are the ids?
martin clayton
INT, but I have already used Asaph's query. Thanks anyways :)
Richard Knop
+2  A: 

I would look at this technique. Your where clause would be WHERE row_number <3

and then limit 30

nick
+2  A: 

Ok, here is a "clever" way to do it:

SELECT u.username, p1.* FROM photos AS p1
 INNER JOIN users AS u ON u.id=p1.user_id
 LEFT OUTER JOIN photos AS p2 ON p2.user_id=p1.user_id and p2.id <= p1.id
 GROUP BY p1.id
 HAVING COUNT(p2.id) <= 3
 LIMIT 30;

Having said that, be weary of "clever" code. It makes you feel good in the near term but maintenance can be painful.

Asaph
This worked :) Thank you very much.
Richard Knop