Eu tenho essa relação N:M:
CREATE TABLE auth_user (
id integer NOT NULL PRIMARY KEY,
username character varying(150) NOT NULL UNIQUE
);
CREATE TABLE auth_group (
id integer NOT NULL PRIMARY KEY,
name character varying(80) NOT NULL UNIQUE
);
CREATE TABLE auth_user_groups (
id integer NOT NULL PRIMARY KEY,
user_id integer REFERENCES auth_user(id) NOT NULL,
group_id integer REFERENCES auth_group(id) NOT NULL,
CONSTRAINT user_groups UNIQUE(user_id, group_id)
);
INSERT INTO auth_user VALUES (1, 'user1');
INSERT INTO auth_user VALUES (2, 'user2');
INSERT INTO auth_group VALUES (1, 'group1');
INSERT INTO auth_group VALUES (2, 'group2');
INSERT INTO auth_user_groups VALUES (1, 1, 1);
INSERT INTO auth_user_groups VALUES (2, 2, 1);
INSERT INTO auth_user_groups VALUES (3, 2, 2);
Como selecionar todos os nomes de usuário que estão no grupo 'group1'?
Eu uso o PostgreSQL, mas o SQL que funciona em todos os lugares é o preferido.
Essa
EXISTS
consulta retorna usuários únicos, independentemente de haver entradas duplicadas emauth_user_groups
.Normalmente rápido também.
Notas
Para Postgres - que você parece estar usando.
A sequência de colunas de índice é importante. Você definiu
UNIQUE(user_id, group_id)
, que é implementado com um índice exclusivo correspondente. Para sua consulta específica, um índice em(group_id, user_id)
seria preferível.Você pode alternar as colunas da
UNIQUE
restrição ou criar um índice adicional (opcionalmente exclusivo) com as colunas invertidas se precisar de ambos (o que é o caso comum). Relacionado:Também esteja ciente de que as colunas incluídas em uma
UNIQUE
restrição ainda podem serNULL
. (Ao contrário de umaPRIMARY KEY
restrição que faz com que todas as colunas de membros sejamNOT NULL
automaticamente!) Você normalmente desejauser_id
e tambémgroup_id
oauth_user_groups
sejaNOT NULL
. Relacionado:Algo assim:
A_horse_with_no_name postou uma boa resposta, na verdade essa era minha opção principal (merecia um upvote =))
Você também pode fazer isso da maneira usual:
Mas observe que, se você tiver mais de um grupo com o mesmo nome e usuários em grupos homônimos, obterá linhas duplicadas:
Nesse caso, você deve usar um distinto:
Observação A resposta A_Horse ainda funciona nesse caso.
A partir do SQL Server 2017 e do Azure SQL DB, você pode usar os novos recursos do banco de dados gráfico e a nova cláusula MATCH para responder a consultas como esta, por exemplo
Meus resultados:
Roteiro completo disponível aqui .