SQL连接表时如何避免冗余行?

问题描述 投票:0回答:1

我正在使用一个包含三个表的数据库:

users
features
和一个
feature_user
连接表来管理哪些用户有权访问哪些功能。以下是包含其他更有用的列的表格:

users
表:

id 用户名 电子邮件 状态
1 约翰 [电子邮件受保护] 活跃
2 [电子邮件受保护] 不活跃
3 约拿 [电子邮件受保护] 活跃

features
表:

id 名字 描述 已启用
1 通知 向用户发送通知 正确
2 csv 导出 将数据导出为 CSV 格式 错误
3 重新设计登陆页面 修改登陆页面布局 正确

feature_user
数据透视表:

用户 ID 功能_id
1 (约翰) 1 (通知)
1 (约翰) 2 (csv 导出)
1 (约翰) 3 (重新设计登陆页面)
2 (简) 1 (通知)
2 (简) 2 (csv 导出)
3 (约拿) 3 (重新设计登陆页面)

当我运行联接查询来列出所有用户及其功能时,对于具有多个功能的用户,我最终会得到冗余行。这是我当前使用的查询:

SELECT fu.user_id, u.username, u.email, u.status, fu.feature_id, f.name AS feature_name, f.description AS feature_description, f.is_enabled
FROM feature_user fu
LEFT JOIN users u ON fu.user_id = u.id
LEFT JOIN features f ON fu.feature_id = f.id;

这将返回以下结果,其中包括具有多个功能的用户的冗余行:

用户 ID 用户名 电子邮件 状态 功能_id 功能名称 功能描述 已启用
1 约翰 [电子邮件受保护] 活跃 1 通知 向用户发送通知 正确
1 约翰 [电子邮件受保护] 活跃 2 csv 导出 将数据导出为 CSV 格式 错误
1 约翰 [电子邮件受保护] 活跃 3 重新设计登陆页面 修改登陆页面布局 正确
2 [电子邮件受保护] 不活动 1 通知 向用户发送通知 正确
2 [电子邮件受保护] 不活动 2 csv 导出 将数据导出为 CSV 格式 错误
3 约拿 [电子邮件受保护] 活跃 3 重新设计登陆页面 修改登陆页面布局 正确

注意

john
并且他的所有数据都重复了3次。

我希望避免查询结果中出现这种冗余,特别是因为分页不是我的用例的选项,并且此查询将在更大的数据集上运行。此外,这些数据最终将通过网络发送回客户端,因此减少冗余将有助于节省带宽并提高性能。

构建查询以避免每个功能重复用户数据,同时保持结果高效和可读的最佳方法是什么?

sql postgresql many-to-many typeorm
1个回答
1
投票

不幸的是,这就是连接的工作原理。如果您想选择所有用户,包括他们的功能,您将得到所谓的“冗余行”。

通过连接,数据库构建所谓的“交叉积”。在您的情况下,数据库正在构建其中两个: feature_user ×

user
x
feature
在构建两个叉积时,数据库会应用您在查询中指定的过滤器(行为可能会因数据库而异)。在你的情况下,这些是:

    fu.user_id = u.id
  • fu.feature_id = f.id
  • 
    
  • 加入并不意味着您将获得一个用户列表,其功能分组在一个数组中。如果你想要它们在一个数组中,你可以这样做(不推荐):

SELECT u.id AS user_id, u.username, u.email, u.status, STRING_AGG(f.name, ', ') AS feature_names FROM users u LEFT JOIN feature_user fu ON fu.user_id = u.id LEFT JOIN features f ON fu.feature_id = f.id GROUP BY u.id, u.username, u.email, u.status;

结果应该是这样的:

用户 ID3[电子邮件受保护]2[电子邮件受保护]1[电子邮件受保护]
用户名 电子邮件 状态 功能名称
约拿 活跃 重新设计登陆页面
不活跃 通知、csv 导出
约翰 活跃 通知、csv 导出、重新设计登陆页面
© www.soinside.com 2019 - 2024. All rights reserved.