【问题标题】:SQL Server Multiple join return duplicated valuesSQL Server 多连接返回重复值
【发布时间】:2021-03-07 02:20:03
【问题描述】:

我的数据库 TEST 下有 4 个表:

  1. 用户
  2. USER_GROUP_PERMISSION
  3. PERMISSION_TYPE

当我使用内连接和交叉连接而不是返回 520 行来连接上述表时,它返回 2600 行,大部分值重复

我需要一个没有重复的最终输出

查询:

select user.*
from TEST.USER user 
    inner join TEST.USER_GROUP_PERMISSION user_grp1
        on user.APPLICATION_ID = user_grp1.APPLICATION_ID 
    inner join TEST.PERMISSION_TYPE permission2_
        on user_grp1.PERMISSION_TYPE_ID = permission2_.PERMISSION_TYPE_ID
    inner join TEST.GROUPS groups
        on user_grp1.GROUP_ID = groups.GROUP_ID
    cross join TEST.PERMISSION_TYPE permission4_ 
where user_grp1.PERMISSION_TYPE_ID = permission4_.PERMISSION_TYPE_ID
    and groups.GROUP_ID in (101)
    and permission4_.PERMISSION_TYPE in (0 , 1 , 2 , 3 , 4 , 5 , 6)
    and user.NAME = 'ROBIN'
    and user.ACTIVE = '1'
order by upper(user.DISPLAY_VERSION) asc

【问题讨论】:

  • 如果您CROSS JOIN,您希望发生什么? CROSS JOIN 将现有数据集中的每一行“连接”到连接表中的每一行。如果您得到“重复”,那么您的 ON 子句或 JOIN 类型是错误的。但如果没有样本数据、预期结果或您试图实现的逻辑,我们无法告诉您更正是什么。

标签: sql sql-server join duplicates


【解决方案1】:

如果您想显示没有重复的用户,请仅从用户中选择。不要加入!查询应该是这样的:

select * from users where ...

您的查询很难理解,尤其是权限类型连接了两次,甚至一次使用伪装成交叉连接的内部连接。看起来您希望用户 ROBIN 处于活动状态并且他的应用程序具有组 101 的组权限并键入 1 到 6。这将是:

select *
from test.user
where name = 'ROBIN'
and active = '1'
and application_id in
(
  select application_id
  from test.user_group_permission
  where group_id = 101
  and permission_type_id in 
  (
    select permission_type_id
    from test.permission_type
    where permission_type in (0, 1, 2, 3, 4, 5, 6)
  )
)
order by upper(display_version);

(你也可以加入permission_typeuser_group_permission,如果你比IN更喜欢的话。)

【讨论】:

  • 它有很大帮助,但查询仍然需要超过 2.5 分钟才能运行。这是一个主要的性能问题。请提出一些解决性能的想法
  • 一个用户2.5分钟???这很奇怪。查询速度几乎总是与索引有关。由于 SQL Server 似乎存在查询问题,我将为每个表提供一个索引及其相关列的排列:permission_type 和列permission_typepermission_type_id 上的两个索引,user_group_permission 的六个索引具有group_idpermission_type_idapplication_id 的所有排列,user 上的六个索引与nameactiveapplication_id
  • 前两个示例:create index idx1 on permission_type (permission_type, permission_type_id);create index idx2 on permission_type (permission_type_id, permission_type);。完成后,检查使用了哪些索引并删除其他索引。
【解决方案2】:

我会使用exists 来表达查询:

select user.*
from TEST.USER user 
where user.NAME = 'ROBIN'
      user.ACTIVE = '1' and
      exists (select 1
              from TEST.USER_GROUP_PERMISSION user_grp1 join
                   TEST.PERMISSION_TYPE permission2_
                   on user_grp1.PERMISSION_TYPE_ID = permission2_.PERMISSION_TYPE_ID join
                   TEST.GROUPS groups
                   on user_grp1.GROUP_ID = groups.GROUP_ID join 
                   TEST.PERMISSION_TYPE permission4_ 
                   on user_grp1.PERMISSION_TYPE_ID = permission4_.PERMISSION_TYPE_ID
              where user.APPLICATION_ID = user_grp1.APPLICATION_ID 
                    groups.GROUP_ID in (101) and
                    permission4_.PERMISSION_TYPE in (0 , 1 , 2 , 3 , 4 , 5 , 6)
       )
order by upper(user.DISPLAY_VERSION) asc

那么,最重要的索引是users(name, active, upper(DISPLAY_VERSION))

【讨论】:

    猜你喜欢
    • 2013-07-22
    • 1970-01-01
    • 2015-07-07
    • 2014-09-09
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    相关资源
    最近更新 更多