简体   繁体   中英

PHP/MySQL - Need assistance writing a SQL Query

I have a martial arts website where I have users in one table and the belts they have earned in another. Here are some example tables / data to help describe my problem:

Users table :

+---------------------+
| Users               |
+---------------------+
| userid | name       |
+---------------------+
|    1   | Fred Smith |
+---------------------+

Belts table :

+------------------------------------------+
| id | userid | belt_colour | awarded_date |
+------------------------------------------+
| 1  |    1   |   blue      |  2007-01-01  |
+------------------------------------------+
| 2  |    1   |   purple    |  2008-01-01  |
+------------------------------------------+
| 2  |    1   |   brown     |  2009-01-01  |
+------------------------------------------+

My problem is this: When you click brown, to view all brown belts I want you to see Fred. I DO NOT want Fred to appear in lists of blue and purple belts (which is what is happening at the moment).

I am struggling to come up with a query that goes something like this:

show me all users where belt=$belt but only if they do not have an entry for a higher belt.

Another example: I am purple but I show up in blue list because details of my blue belt are in the belts table too :-(

Any assistance greatly appreciated!

Assuming a higher belt means a higher awarded_date, one option is to get the MAX of awarded_date for each user and join back to the belt table:

SELECT u.userId, u.name
FROM Users u
    JOIN (
        SELECT userId, MAX(awarded_date) max_awarded_date
        FROM Belts
        GROUP BY userId
   ) maxb ON u.userId = maxb.userId
   JOIN Belts b ON b.userId = maxb.userId 
       AND b.awarded_date = maxb.max_awarded_date
WHERE b.belt_colour = 'brown'

Sort by _awarded_date_ descending. And limit 1 to the result.

Since every Belt is awarded one after the other, the most recent, is the one that you want to show. So, your query would be like this:

 select * from Users u, Belts b where u.userid = b.userid order by awarded_date limit 1;

Hope this helps.

Let's split this problem in two:

  1. First, you need to show the most recent belt for every person
  2. Then you need to show the people that has a belt

So, let's start.

Step 1.a. The most recent belt record for every user

select b.*
from 
    belts as b
    inner join (
        select max(id) as maxId from belts group by userId
    ) as a on b.id = a.maxId

I am assuming that the id field is always incremental.

Step 1.b. Join step (1.a.) with the user's data

select u.*, b.*
from 
    users as u
    inner join (
    select b.*
    from 
        belts as b
        inner join (
            select max(id) as maxId from belts group by userId
        ) as a on b.id = a.maxId
    ) as b on u.userId = b.userId

Step 2. Select all users with a given belt

select u.*, b.*
from 
    users as u
    inner join (
    select b.*
    from 
        belts as b
        inner join (
            select max(id) as maxId from belts group by userId
        ) as a on b.id = a.maxId
    ) as b  on u.userId = b.userId
where
    b.belt_colour = 'brown'

Hope this helps

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