【问题标题】:SQL query to find users with apps with no releasesSQL 查询以查找未发布应用的用户
【发布时间】:2019-03-12 15:17:24
【问题描述】:

在我的数据库中,我有用户、应用程序和版本。一个用户可以通过权限表拥有 0..n 个应用,一个应用可以拥有 0..n 个版本。

我正在尝试获取至少拥有 1 个应用程序的用户列表,但该用户的应用程序都没有任何版本。

架构大致

users  permissions  apps  releases
-----  -----------  ----  --------
id     user_id      id    id
email  app_id             app_id

认为我有一些东西可以解决这个问题,但对我来说似乎效率低下,因为我提到了两次权限表并且我正在使用嵌套的存在子句。有没有更有效的方法来编写这个查询?

select u.email from users u 
    join permissions p on p.user_id = u.id 
    where not exists (
        select a.id from apps a 
            join permissions p on p.app_id = a.id 
            where p.user_id = u.id and exists (
                select r.id from releases r 
                    where r.app_id = a.id
            )
    ); 

【问题讨论】:

标签: mysql sql performance join exists


【解决方案1】:

您只需要在发布时使用LEFT JOIN,然后查找已发布应用数(r.app_id 为非NULL)为0 的情况。如果您想要的只是用户列表,我认为您根本不需要 JOIN apps 表,因为 JOINing on permissions 将确保仅包含对 1 个或多个应用程序具有权限的用户。

SELECT u.email
FROM users u
JOIN permissions p ON p.user_id = u.id
LEFT JOIN releases r ON r.app_id = p.app_id
GROUP BY u.email
HAVING COUNT(r.app_id) = 0

【讨论】:

  • 一开始我在想这样的事情,但假设用户 A 对 APP1 和 APP2 具有权限,其中 APP1 有发布,而 APP2 没有任何发布。我认为该用户将被选中,但与此相矛盾:但该用户的应用程序都没有任何版本
  • @D.Smania 你是绝对正确的。感谢您指出这一点。
【解决方案2】:

userspermissions 表之间的第一个 Join 似乎是正确的。您只需要检查加入结果集中的 app_id 是否存在于releases 表中。你可以试试这个查询 -

select u.email from users u 
join permissions p on p.user_id = u.id 
where not exists ( Select 1 from releases r where r.App_id = p.app_id)

【讨论】:

  • 这将显示一个用户,该用户对APP1和APP2有权限,但只发布了APP2,不符合问题标准“该用户的应用没有任何发布 "
【解决方案3】:

我会做这样的事情,希望这会有所帮助:

SELECT
    u.id, u.email
FROM
    users AS u
INNER JOIN
    permissions AS p ON p.user_id = u.id
LEFT JOIN
    releases AS r ON r.app_id = p.app_id
GROUP BY
    u.id, u.email
HAVING
    SUM(CASE WHEN r.id IS NOT NULL THEN 1 ELSE 0 END) = 0

【讨论】:

    【解决方案4】:

    您可以尝试的另一件事是左连接和内连接的组合,如下所示:

    Select
        email
    From users u
    Inner Join (
        Select
            p.user_id
            , p.app_id
         From permissions p
         Left Join releases r
            on p.app_id = r.app_id
         Where r.app_id is null) a
    on u.user_id = a.user_id
    Group by email
    

    如果不知道不同表的大小(因此 SQL 将尝试加入多少行),很难判断此解决方案与之前发布的解决方案哪个更快。

    有一点很清楚 - 如果最后没有“按电子邮件分组”行,您可能会看到用户的电子邮件在您的列表中重复了多次。通常,有关 SQL 的文献指出,在查询末尾使用“group by”语句比在查询开头使用“select distinct”语句更快地获得不同的集合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-12
      • 1970-01-01
      • 1970-01-01
      • 2022-08-16
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 2018-11-11
      相关资源
      最近更新 更多