Select project_ID
from user_projects
where user_ID in (1,2)
group by project_ID
Having count(*) = 2
Você sabe que tem 2 usuários, você sabe que eles serão únicos (chave primária) então você sabe que se houver 2 registros, para o mesmo projeto, então é aquele que você deseja.
Sua pergunta indicou que você tem um dado enviado de usuários para que você saiba quais usuários e quantos são. o SQL acima pode ser atualizado para aceitar parâmetros para estes conhecidos e assim permanece dinâmico, não limitado a apenas 2 usuários.
where user_ID in (userlist)
having count(*) = (cntuserList)
-----------Para lidar com a situação quando o conjunto de usuários está vazio-----
Select P.project_ID
from Projects P
LEFT JOIN user_projects UP
where (UP.user_ID in (1,2) OR UP.USER_ID is null)
group by project_ID
Having count(*) = 2
Então aqui está o que isso faz. Ele retorna todos os projetos e se houver um usuário afiliado a esse projeto ele os identifica. Se você definir contém usuários, a lista de projetos retornados é filtrada por esse conjunto garantindo que todo o conjunto esteja no projeto através da cláusula havendo.
Se o conjunto estiver vazio, a junção LEFT junto com a instrução userID is null manterá os projetos sem usuários listados, independentemente de o conjunto estar vazio ou não. A cláusula having reduzirá ainda mais o conjunto para o número de usuários que você definiu no conjunto, OU 0 indicando retornar todos os projetos sem usuários atribuídos.
Um caso adicional que ainda não discutimos é o que deve acontecer se um projeto contiver mais usuários do que você definiu no conjunto. Atualmente este projeto seria devolvido; mas não tenho certeza de que era isso que você queria.
em uma nota lateral obrigado por me fazer pensar. Eu não consigo mais entrar no código; é por isso que eu trollo aqui de vez em quando para ver se posso ajudar!