【问题标题】:Unify columns from different tables while selecting distinct rows在选择不同的行时统一来自不同表的列
【发布时间】:2023-04-06 18:11:01
【问题描述】:

表格

用户

id name email is_active
1 john john@albert.com FALSE
2 mike mike@ss.com TRUE
3 monica monica@dunno.com TRUE
4 joey joey@as.com FALSE
5 ross ross@boss.com FALSE

订阅

id house_id plan name status
1 1 A banana a month inactive
2 2 An apple a month active
3 3 A pear a month active

房子

id name
1 John's House
2 Mike's House
3 Monica's House
4 Joey's House
5 Ross's House

House_Contact(旧表)

id house_id is_primary
1 1 TRUE
2 2 FALSE
2 3 TRUE

House_User(新表)

id house_id is_owner user_id
1 2 FALSE 2
2 4 FALSE 4
3 5 FALSE 5

预期结果

结果表应包括以下内容:

  • 无论状态如何,用户是否都有订阅?如果是,请包括,如果不是,请忽略。
  • 从用户表中获取email & is_active(如果他们有订阅)
  • 获取is_primaryis_owner(如果他们有订阅)
  • 结果应该是不同的(没有重复的用户)
house_id email is_owner is_active
1 john@albert.com TRUE FALSE
2 mike@ss.com FALSE TRUE
3 monica@dunno.com TRUE TRUE

我尝试了什么

SELECT
    u.email AS "email",
    u.is_active AS "is_active",
    h.id AS "house_id",
    is_owner
FROM
    house c
    INNER JOIN (
        SELECT
            house_id,
            user_id
        FROM
            house_user) hu ON h.id = hu.house_id
    INNER JOIN (
        SELECT
            id,
            email,
            is_active
        FROM
            USER) u ON hu.user_id = u.id
    INNER JOIN (
        SELECT
            id,
            email,
            is_primary
        FROM
            house_contact) hc ON u.email = ch.email
    INNER JOIN (
        SELECT
            house_id,
            is_primary is_owner
        FROM
            house_contact
    UNION
    SELECT
        house_id,
        is_owner is_owner
    FROM
        house_user) t ON u.id = t.house_id)
ORDER BY
    u.email

结果是我删除 INNER JOINUNION 语句的一半。不知道如何继续。

我对统一列和可能的重复感到特别困惑。

【问题讨论】:

  • 你能用英语解释一下结果吗?逻辑不明显。还不清楚这些表是如何相互关联的。它们都有 id,但什么 id 对应什么?
  • 你能为这个问题创建一个fiddle 吗?
  • 你为什么要做....INNER JOIN (SELECT ..... table ) ON.... 而不是更简单的..INNER JOIN table ON .... ???
  • 当数据中没有真值时,is_owner 如何变为“真”?
  • 这不是您尝试的代码。 “用户”是保留字。 FROM USER 会引发错误。您是否简化了表名?最后是无与伦比的)。另外:如果is_primaryis_owner 同时存在,那么哪个优先?我们需要知道显示所有约束(特别是 PK、FK 和 NOT NULL)的实际表定义才能确定。并且总是你的 Postgres 版本,以防万一。

标签: sql postgresql duplicates left-join greatest-n-per-group


【解决方案1】:

我有根据的猜测:

SELECT DISTINCT ON (u.id)
      u.id, u.email, u.is_active, h.house_id, h.is_primary
FROM  "user" u
LEFT  JOIN (
   SELECT hu.user_id, hu.house_id
        , GREATEST(hc.is_primary, hu.is_owner) AS is_primary
   FROM   house_user hu
   LEFT   JOIN house_contact hc USING (house_id)
   WHERE  EXISTS (SELECT FROM subscription WHERE house_id = hu.house_id)
   ) h ON h.user_id = u.id
ORDER  BY u.id, h.is_primary DESC NULLS LAST, h.house_id;

我们在查询中根本不需要表house

我看到三个可能的冲突来源:

  1. house_contact.is_primaryhouse_user.is_owner。两者的意思似乎相同。 DB设计在这方面被打破了。取两者的GREATEST(),这意味着true,如果其中一个是true

  2. 我们不关心subscription.status,所以只要确保房子至少有一个订阅EXISTS,从而避免可能的重复。

  3. 一个用户可以住在多个房子里。我们希望每个用户只有 一个 行。因此,如果有的话,用is_primary(最小的house_id)显示第一个房子。如果没有房子,也没有订阅。但是外部LEFT JOIN 将用户保留在结果中。更改为JOIN 以跳过未订阅的用户。

关于DISTINCT ON

关于排序布尔值:

【讨论】:

    【解决方案2】:

    您可以按如下方式使用joins

    Select distinct hu.house_id, u.email, hu.is_owner, hc.is_primary
      From user u join house_user hu on u.id = hu.user_id
      Join subscriptions s on s.house_id = hu.house_id
      Join house_contract hc on hc.house_id = s.house_id;
    

    如果表中有多个数据匹配条件,我已使用distinct 删除重复项。如果不需要,您可以将其删除。

    【讨论】:

      【解决方案3】:

      据我所知,您希望从这样的查询开始:

      select s.house_id, u.email, hu.is_owner, u.is_active      
      from subscriptions s left join
           house_user hu
           on s.house_id = hu.house_id left join
           users u
           on hu.user_id = u.id;
      

      这不会返回您想要的结果,但不清楚您的结果是如何得出的。

      【讨论】:

      • 这就是我要解决的问题。一些用户在house_contact 旧表中,一些用户在house_user 新表中。它们可能重复或仅包含在一张表中。所以我需要查询两者的结果并将is_primary列与is_owner统一起来。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-11-14
      • 1970-01-01
      • 2018-01-09
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 2023-02-26
      相关资源
      最近更新 更多