查询以返回至少一个关联数据与要求匹配的所有记录(包括所有关联数据)

时间:2014-04-18 14:56:38

标签: sql postgresql

表:

Users
Roles
RolesUsers

社团:

User hasMany Role through RolesUsers
Role hasMany User through RolesUsers

我想要的是让所有用户以及所有角色(用户)包含符合给定要求的至少一个角色

我使用此查询来获取与Role.name = 'admin' or 'member'关联的所有用户。 它有效,但与每个User一起,它只返回与查询匹配Roles的{​​{1}}。如果用户与名为name的角色关联,则不会返回 - 我如何包含所有相关角色?

author

3 个答案:

答案 0 :(得分:1)

SELECT
    u.*
    , r."name" AS "Roles.name"
    , r."id" AS "Roles.id"
    , ru."createdAt" AS "createdAt"
    , ru."updatedAt" AS "updatedAt"
    , ru."UserId" AS "UserId"
    , ru."RoleId" AS "RoleId"
FROM "Users" u 
JOIN "RolesUsers" ru ON u."id" = ru."UserId" 
JOIN "Roles" r ON r."id" = ru."RoleId" 
WHERE EXISTS (
        SELECT *
        FROM "RolesUsers" ru2
        JOIN  "Roles" r2  ON r2."id" = ru2."RoleId"
        WHERE ru2."UserId" = u."Id"
        AND r2."name" IN ( 'member' , 'admin' )
        )
        ;

答案 1 :(得分:0)

我会将分析函数用于此目的,如下所示:

select ur.*
from (select u.*, ru.name as rolename, ru.id as roleid, ru.createdAt as rolecreatedat,
             sum(case when ru.name in ('member', 'admin') then 1 else 0 end) over (partition by u.id) as NumMatches
      from users u join
           roleusers as ru
           on u.id = ru.userid
     ) ur
where NumMatches > 1;

我不明白你的表别名方案,你使表名比他们需要的更复杂。缩写通常使查询更具可读性。

答案 2 :(得分:0)

您已通过INNER JOIN连接UsersRolesUsers,我认为在这种情况下您需要LEFT JOIN。

SELECT "Users".*, "Roles"."name" AS "Roles.name", "Roles"."id" AS "Roles.id", "Roles.RolesUser"."createdAt" AS "Roles.RolesUser.createdAt", "Roles.RolesUser"."updatedAt" AS "Roles.RolesUser.updatedAt", "Roles.RolesUser"."UserId" AS "Roles.RolesUser.UserId", "Roles.RolesUser"."RoleId" AS "Roles.RolesUser.RoleId" 
FROM (
    SELECT "Users".* 
    FROM "Users" 
    WHERE (
        SELECT "UserId" 
        FROM "RolesUsers" AS "Roles.RolesUser" 
        INNER JOIN "Roles" AS "Roles" ON "Roles"."id" = "Roles.RolesUser"."RoleId" 
        WHERE "Users"."id" = "Roles.RolesUser"."UserId" AND "Roles"."name" IN ('member','admin') LIMIT 1
    ) IS NOT NULL LIMIT 100
) AS "Users" 
LEFT JOIN "RolesUsers" AS "Roles.RolesUser" ON "Users"."id" = "Roles.RolesUser"."UserId" 
INNER JOIN "Roles" AS "Roles" ON "Roles"."id" = "Roles.RolesUser"."RoleId" AND "Roles"."name" IN ('member','admin');