简体   繁体   中英

Is there a better way to do this query?

I'm kind of new to MYSQL, this query works but wonder if there's a more efficient way. I have 2 tables... client_table and client_skills . Both tables have a 'client_id' column. I'm trying to select only the clients that match all of the requested skill code and types

This is what I first tried... (doesn't work unless you change AND to OR)

SELECT * FROM client_table
LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
WHERE (skill_code='97' AND skill_type='0')
AND (skill_code='65' AND skill_type='0')
AND (skill_code='23' AND skill_type='5')

Then I tried this... (which works and returns the results I want it to)

SELECT * FROM client_table
WHERE client_id IN 
(SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0'))
AND client_id IN
(SELECT client_id FROM client_skills WHERE (skill_code='65' AND skill_type='0'))
AND client_id IN
(SELECT client_id FROM client_skills WHERE (skill_code='23' AND skill_type='5'))

But if there is a shorter or more efficient way to do that I'd love to learn it. Thanks for your help

the second one is slower than the first one since you are doing 4 queries, so between those two example just go with the first one with OR instead of AND.

There may be better/faster queries, but that depends on the requirements and your table's indexes

For example, do you really need skill_type? can you have two skills with the same code and different type? if all skill codes are different, just do:

SELECT * FROM client_table
LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
WHERE skill_code IN ('97','65','23')

if you have an index on skill_code then the query would be faster too

EDIT: ok, now I understand your question, you need at least 2 queries, one to get all client ids that matches the tree skills and one to get clients with those ids, try this:

SELECT * from client_table WHERE client_id IN (
  SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0') OR 
  (skill_code='65' AND skill_type='0') OR (skill_code='23' AND skill_type='5')
  GROUP BY client_id HAVING count(*) = 3)

what you are doing there is:

  1. get all client_skills records the matches any of your three desired skills
  2. group them by client_id
  3. select only the client_id for groups that has exactly 3 records (it means those groups have all three skills)
  4. select all clients who's ids are in the ids returned by the subquery

I think that's be fastest approach, only 2 queries, I don't think it can be done with just one query

NOTE: that query is not tested, it's the idea, you may need to play a little with HAVING and GROUP_BY

your 1st query modified using OR is not bad. and you can do with UNION :

SELECT client_id FROM client_skills WHERE (skill_code='97' AND skill_type='0')
UNION
SELECT client_id FROM client_skills WHERE (skill_code='65' AND skill_type='0')
UNION
SELECT client_id FROM client_skills WHERE (skill_code='23' AND skill_type='5')

EDITED

you can accomplish something like this. SELF JOIN is required. (not tested on you data):

SELECT t1.client_id
FROM client_skills t1 JOIN client_skills t2 ON t1.client_id = t2.client_id
            AND t1.skill_code='97' AND t1.skill_type='0'
            AND t2.skil_code='65' AND t2.skill_type='0'
    JOIN client_skills t3 ON t3.client_id = t1.client_id
            AND t3.skil_code='23' AND t3.skill_type='5'

is this what you're asking for since you wanted to use AND instead of OR sqlFiddle example in my example only has all 3 skills (of that skill_code and skill_type) 拥有全部3种技能(该skill_code和skill_type)

SELECT c.*
FROM client_table c,
     client_skills s1,
     client_skills s2,
     client_skills s3
WHERE
      c.client_id = s1.client_id AND s1.skill_code=97 AND s1.skill_type=0
  AND c.client_id = s2.client_id AND s2.skill_code=65 AND s2.skill_type=0
  AND c.client_id = s3.client_id AND s3.skill_code=23 AND s3.skill_type=5

It's the same logic as your second query.

SELECT
    client_table.*
    ,SUM(
        IF( skill_code='97' AND skill_type='0' ,1 ,0 )
        +
        IF( skill_code='65' AND skill_type='0' ,1 ,0 )
        +
        IF( skill_code='23' AND skill_type='5' ,1 ,0 )
    ) AS skill_code_type_count
FROM
    client_table
    LEFT JOIN client_skills ON client_table.client_id = client_skills.client_id
GROUP BY
    client_table.client_id
HAVING
    skill_code_type_count >= 3

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