MYSQL selezionando gli utenti con competenze specifiche
-
20-09-2019 - |
Domanda
Sono cavarsela mia strada attraverso di gran lunga la query SQL più complesse che abbia mai fatto, che è probabilmente estremamente semplice per la maggior parte di voi (:
Ho tre tabelle, per l'utente, le competenze e l'User_Skills. I campi di cui dovrebbero essere abbastanza autoesplicativo.
Voglio scegliere le persone che hanno una o più abilità che soddisfano i miei criteri.
Posso selezionare un utente con l'abilità che sto cercando, ma non sono sicuro sulla sintassi per l'interrogazione molteplici competenze.
mi piacerebbe usare solo una query, quindi sto cercando di usare group_concat
Ecco il mio SQL:
SELECT User_id, first_name, last_name, county, GROUP_CONCAT(CAST(Skill_id AS CHAR))
FROM User LEFT JOIN User_Skills ON User.id = User_Skills.User_id
LEFT JOIN Skills ON User_Skills.Skill_id = Skills.id GROUP BY User_id
User_id first_name last_name county GROUP_CONCAT(CAST(Skill_id AS CHAR))
1000 Joe Blow West Yorkshire 8,6,1,9,7,3,5,10
1001 Fred Bloggs COUNTY1 5,8,2,7,9
1003 asdf asdf1 Some County 10,8,2
Come faccio a limitare la ricerca a solo le persone che hanno abilità 5 e 9?
Soluzione
SELECT *
FROM users u
WHERE EXISTS
(
SELECT NULL
FROM user_skills us
WHERE us.skill_id IN (5, 9)
AND us.user_id = u.id
LIMIT 1, 1
)
Questo si basa sul fatto che è un (user_id, skill_id)
PRIMARY KEY
o un tasto UNIQUE
(cioè non è possibile assegnare una competenza a un utente più di una volta).
Aggiornamento:
Per tornare tutte le abilità (separati da virgola):
SELECT u.*,
(
SELECT GROUP_CONCAT(skill_id)
FROM user_skills uso
WHERE uso.user_ud = u.user_id
) AS all_skills
FROM users u
WHERE EXISTS
(
SELECT NULL
FROM user_skills us
WHERE us.skill_id IN (5, 9)
AND us.user_id = u.id
LIMIT 1, 1
)
Altri suggerimenti
SELECT User_id, first_name, last_name, county, GROUP_CONCAT(CAST(Skill_id AS CHAR))
FROM User JOIN User_Skills ON User.id = User_Skills.User_id
JOIN Skills ON User_Skills.Skill_id IN (5,9)
GROUP BY User_id
Se si vuole evitare che più record di abilità, allora potrebbe essere necessario un subquery
SELECT User_id, first_name, last_name, county,
(
SELECT (GROUP_CONCAT(CAST(subSkill.Skill_id AS CHAR))
FROM Skills as subSkill WHERE subSkill.skill_id = User_Skills.skill_id
GROUP BY subSkill.skill_id
)
FROM User JOIN User_Skills ON User.id = User_Skills.User_id
JOIN Skills ON User_Skills.Skill_id IN (5,9)
GROUP BY User_id
Perché non puoi semplicemente utilizzare un INNER JOIN inplace della LEFT JOIN, ed emettere una clausola WHERE per le competenze necessarie?
SELECT User_id, first_name, last_name, county, GROUP_CONCAT(CAST(Skill_id AS CHAR))
FROM User
INNER JOIN User_Skills ON User.id = User_Skills.User_id
INNER JOIN Skills ON User_Skills.Skill_id = Skills.id GROUP BY User_id
WHERE skill_id = 5 OR skill_id=9
Ecco come (vi darà agli utenti con competenze 5 e 9):
SELECT User_id, first_name, last_name, county FROM User INNER JOIN User_Skills ON User.id = User_Skills.User_id INNER JOIN Skills ON User_Skills.Skill_id = Skills.id WHERE Skills.Skill_id = 5 AND Skills.Skill_id = 9 GROUP BY User_id
Hai solo bisogno di un
HAVING FIND_IN_SET('5', skills) AND FIND_IN_SET('9', skills)
dopo che il gruppo da (in cui "competenze" è il nome della colonna raggruppate). Quindi la query dovrebbe apparire come
SELECT User_id, first_name, last_name, county, GROUP_CONCAT(CAST(Skill_id AS CHAR)) as skills
FROM User LEFT JOIN User_Skills ON User.id = User_Skills.User_id
LEFT JOIN Skills ON User_Skills.Skill_id = Skills.id GROUP BY User_id
HAVING FIND_IN_SET('5', skills) AND FIND_IN_SET('9', skills)