在选择不同的行时统一来自不同表的列
Posted
技术标签:
【中文标题】在选择不同的行时统一来自不同表的列【英文标题】:Unify columns from different tables while selecting distinct rows 【发布时间】:2021-03-23 17:22:11 【问题描述】:表格
用户
id | name | 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_primary
或is_owner
(如果他们有订阅)
结果应该是不同的(没有重复的用户)
house_id | 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 JOIN
和 UNION
语句的一半。不知道如何继续。
我对统一列和可能的重复感到特别困惑。
【问题讨论】:
你能用英语解释一下结果吗?逻辑不明显。还不清楚这些表是如何相互关联的。它们都有 id,但什么 id 对应什么? 你能为这个问题创建一个fiddle 吗? 你为什么要做....INNER JOIN (SELECT ..... table ) ON....
而不是更简单的..INNER JOIN table ON ....
???
当数据中没有真值时,is_owner
如何变为“真”?
这不是您尝试的代码。 “用户”是保留字。 FROM USER
会引发错误。您是否简化了表名?最后是无与伦比的)
。另外:如果is_primary
和is_owner
同时存在,那么哪个优先?我们需要知道显示所有约束(特别是 PK、FK 和 NOT NULL)的实际表定义才能确定。并且总是你的 Postgres 版本,以防万一。
【参考方案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
。
我看到三个可能的冲突来源:
house_contact.is_primary
与 house_user.is_owner
。两者的意思似乎相同。 DB设计在这方面被打破了。取两者的GREATEST()
,这意味着true
,如果其中一个是true
。
我们不关心subscription.status
,所以只要确保房子至少有一个订阅EXISTS
,从而避免可能的重复。
一个用户可以住在多个房子里。我们希望每个用户只有 一个 行。因此,如果有的话,用is_primary
(最小的house_id
)显示第一个房子。如果没有房子,也没有订阅。但是外部LEFT JOIN
将用户保留在结果中。更改为JOIN
以跳过未订阅的用户。
关于DISTINCT ON
:
关于排序布尔值:
Sorting null values after all others, except special Sort NULL values to the end of a table【讨论】:
【参考方案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
统一起来。以上是关于在选择不同的行时统一来自不同表的列的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 11g 文本:复合域索引 - 对来自不同表的列进行过滤
在 s-s-rS Report Builder Execute(@Query) 中对列标题使用动态 SQL - 使用来自 1 个表的值作为来自不同表的值的列标题