MYSQL seleccionando usuarios con habilidades específicas
-
20-09-2019 - |
Pregunta
Estoy lidiando con la consulta SQL más compleja que he hecho jamás, que probablemente sea extremadamente simple para la mayoría de ustedes (:
Tengo tres tablas, Usuario, Habilidades y User_Skills.cuyos campos deberían explicarse por sí solos.
Quiero elegir personas que tengan una o más habilidades que cumplan con mis criterios.
Puedo seleccionar un usuario con la habilidad que busco, pero no estoy seguro de la sintaxis para consultar múltiples habilidades.
Me gustaría usar solo una consulta, así que estoy intentando usar GROUP_CONCAT
Aquí está mi 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
¿Cómo limito la búsqueda solo a personas que tengan las habilidades 5 y 9?
Solución
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
)
Esto se basa en el hecho de que es un (user_id, skill_id)
PRIMARY KEY
o una llave UNIQUE
(es decir no se puede asignar una habilidad a un usuario más de una vez).
Actualización:
Para devolver todas las habilidades (separados por comas):
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
)
Otros consejos
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
Si desea evitar múltiples registros de habilidades, es posible que necesite una subconsulta
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
¿Por qué no puede usted sólo tiene que utilizar un INNER JOIN in-situ de la combinación izquierda, y emitir una cláusula WHERE de las habilidades requeridas?
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
Así es como (que dará a los usuarios con habilidades 5 y 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
Sólo se necesita un
HAVING FIND_IN_SET('5', skills) AND FIND_IN_SET('9', skills)
después de que el grupo por (donde "habilidades" es el nombre de la columna agrupado). Así que la consulta debe parecerse
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)