简体   繁体   中英

How to query a table (which has multiple rows pertaining to a single entity) and return GROUPED result but only where all conditionals have been met?

Firstly, pardon the incredibly vague/long question, I'm really not sure how to summarise my query without the full explanation.

Ok, I have a single MySQL table with the format like so

some_table

  • user_id
  • some_key
  • some_value

If you imagine that, for each user, there are multiple rows, for example:

1   |  skill   |   html
1   |  skill   |   php
1   |  foo     |   bar
2   |  skill   |   html
3   |  skill   |   php
4   |  foo     |   bar

If I want to find all the users who have listed HTML as a skill I can simply do:

SELECT user_id
FROM some_table
WHERE some_key = 'skill' AND some_value='html'
GROUP BY user_id

Easy enough. This would give me user ID's 1 and 2.

If I want to find all users who have listed HTML or PHP as a skill then I can do:

SELECT user_id
FROM some_table
WHERE (some_key = 'skill' AND some_value='html') OR (some_key = 'skill' AND some_value='php')
GROUP BY user_id

This would give me use ID's 1, 2 and 3.

Now, what I'm struggling to work out is how I can query the same table but this time say "give me all the users who have listed both HTML and PHP as a skill", ie: just user ID 1.

Any advice, guidance or links to docs massively appreciated.

Thanks.

Here's one way:

SELECT user_id
FROM some_table
WHERE user_id IN (SELECT user_id FROM some_table where (some_key = 'skill' AND some_value='html'))
AND user_id IN (SELECT user_id FROM some_table where (some_key = 'skill' AND some_value='php'))

I don't know if this is valid for mysql, but should be (works for other db engines):

 SELECT php.user_id 
 FROM some_table php, some_table html 
 WHERE php.user_id = html.user_id 
   AND php.some_key = 'skill' 
   AND html.some_key = 'skill' 
   AND php.some_value = 'php' 
   AND html.some_value = 'html';

And alternative, by using HAVING statement:

SELECT user_id, count(*) 
FROM some_table 
WHERE some_key = 'skill' 
  AND some_value in ('php','html') 
GROUP BY user_id 
HAVING count(*) = 2;

And a third option is to use inner selects. A slight alternative approach to David's approach:

SELECT user_id FROM some_table
WHERE 
   some_key = 'skill' AND
   some_value = 'html' AND
   user_id IN (
       SELECT user_id FROM some_table 
       WHERE 
           some_key = 'skill' AND
           some_value = 'php' AND 
           user_id IN (
               SELECT user_id FROM some_table 
               WHERE 
                   some_key = 'skill' AND
                   some_value = 'js' -- AND user_id IN ... for next level, etc.
           )
    );

... idea is that you can "pipe" the inner selects. With each new property you add new inner select to the most inner one.

you need to use a nested query (or a self join, which is different)

I set up the following table.

+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| type  | char(10) | YES  |     | NULL    |       |
| value | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+

inserted the following values

+------+-------+-------+
| id   | type  | value |
+------+-------+-------+
|    1 | skill | html  |
|    1 | skill | php   |
|    2 | skill | html  |
|    3 | skill | php   |
|    2 | skill | php   |
+------+-------+-------+

ran this query

select id 
from test 
where type = 'skill' 
and value = 'html' 
and id in (
select id 
from test 
where type = 'skill' 
and value = 'php');

and got

+------+
| id   |
+------+
|    1 |
|    2 |
+------+

a self join would be as follows

select e1.id
from test e1, test e2
where e1.id = e2.id
and e2.type = 'skill'
and e2.value = 'html'
and e1.type = 'skill'
and e1.value = 'php'
;

and produce the same result.

so there you have two ways to try it in your code.

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