简体   繁体   中英

Get one row for each group with order and limit

I have records of photos that users have uploaded in my database. They can specify one of the photos they have uploaded as being a cover photo.

I'd like to query my database to return one photo for each username. If they have cover photo, return that one. If not, pull a normal photo. The column to specify a cover photo is tinyint with a length of 1. The column is either "0"(not a cover photo) or "1"(a cover photo).

I have the following to return all photos for the list of usernames

$usernames = array('bob', 'ted', 'jim');
$usernames = implode( "', '", $usernames );

$query = "SELECT * FROM Photos WHERE username IN('$usernames')";

but i need to combine it with the following, which gets a cover photo if there is one and a normal photo if there isn't for one username.

$query = "SELECT * FROM Photos WHERE username = 'bob' ORDER BY cover DESC LIMIT 1";

I think I need to use the GROUP BY function but I don't know how to set that up. Any suggestions?

Columns are id(bigint), name(varchar(255)), cover(tinyint), username(varchar(30))

Assuming you have a user table and the photo table has an id column

SELECT p.*
FROM Users u 
INNER JOIN Photo p ON p.id = (
    SELECT id FROM Photos p2 
    WHERE p2.username = u.username 
    ORDER BY cover DESC 
    LIMIT 1
)
WHERE u.username IN('$usernames');

If you only want 1 photo per user (cover if it exists, normal if no cover exists)

SELECT max( cover ) , username, photo
FROM Photos
WHERE username IN('$usernames')
GROUP BY username 

If you want all normal photos, and only 1 cover photo (if it exists), you can do

SELECT * FROM Photos WHERE cover = 1 AND username IN ('$usernames') GROUP BY username
UNION
SELECT * FROM Photos WHERE cover = 0 AND username IN ('$usernames')

If each record has a Unique identifier ( id ), you can do the following:

SELECT P1.* FROM Photos P1
WHERE P1.id IN (SELECT P2.id FROM Photos P2 
                WHERE P2.username =P1.username 
                ORDER BY P2.cover DESC LIMIT 1)
AND P1.username IN ('$usernames')
ORDER BY P1.username

In Mysql, you need to do something like:

select p.*
from Photos p left outer join
     (select username, min(photoid) as minphotoid
      from photos p
      where cover = 0
      group by username
     ) pmin
     on p.username = pmin.username and
        (p.cover = 1 or p.photoid = pmin.minphotoid)
where p.username in ('$usernames')

This is essentially finding one photo (the minimum one) when there is no cover or the cover. There are variations on this with a correlated subquery, which could be faster.

By the way, does p.username in ('$usernames') work in mysql? In other databases, this would only work with one user name in $usernames.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM