MySQL selecionando usuários com habilidades específicas
-
20-09-2019 - |
Pergunta
Estou de longe, estou de longe a consulta SQL mais complexa que já fiz, o que provavelmente é extremamente simples para a maioria de vocês (:
Eu tenho três tabelas, usuário, habilidades e user_skills. Cujos campos devem ser bastante auto -explicativos.
Quero escolher pessoas que tenham uma ou mais habilidades que atendam aos meus critérios.
Posso selecionar um usuário com a habilidade que estou buscando, mas não tenho certeza sobre a sintaxe para consultar várias habilidades.
Eu gostaria de usar apenas uma consulta, então estou tentando usar o group_concat
Aqui está o meu 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
Como limito a pesquisa a apenas pessoas que têm habilidade 5 e 9?
Solução
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
)
Isso depende do fato de que (user_id, skill_id)
é um PRIMARY KEY
ou a UNIQUE
chave (ou seja, você não pode atribuir uma habilidade a um usuário mais de uma vez).
Atualizar:
Para devolver todas as habilidades (vírgula separada):
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
)
Outras dicas
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 você deseja evitar vários registros de habilidades, pode precisar de uma 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 que você não pode simplesmente usar uma junção interna no lugar da junção esquerda e emitir uma cláusula onde as habilidades necessárias?
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
Veja como (dará a você usuários com habilidades 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
Você só precisa de um
HAVING FIND_IN_SET('5', skills) AND FIND_IN_SET('9', skills)
Após o grupo (onde "habilidades" é o nome da coluna agrupada). Então sua consulta agora deve parecer
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)