过滤具有一对多父子映射的表的最有效方法

Posted

技术标签:

【中文标题】过滤具有一对多父子映射的表的最有效方法【英文标题】:Most efficient way to filter a table with 1 to many parent and child mappings 【发布时间】:2018-12-06 20:52:49 【问题描述】:

我有一个客户表,它自身有一个外键,其中每个客户在每个部门都有一个特定的 ID,但只有一个主 ID。我正在尝试找到最有效的方法来将我的查询限制在主条目中。

这里有两个(简化的)查询,但我觉得有一种更有效的方法可以完成这项工作,尤其是在加入其他大表时:


-- version 1
select 
    client.id
from
    client
        join client client2 on client.id = client2.masterid 
                               and client2.id = client2.masterid

--version 2

select 
    client.id,
from
    client
where
    client.id = client.masterid

-- Expanded view
select
t1.id masterid,
t1.dob dob,
trunc((months_between(trunc(sysdate),t1.dob)/12),0) age,
case
    when substr(t1.zip,1,5) in ('48502','48503','48504','48505','48506','48507','48529','48532') then null 
else
(select
    max(audit1.operationid)
from
    t2 audit1
where
    t1.id = audit1.sourceid                                                                                             
    and audit1.fieldname = 'ZIP'
    and substr(audit1.oldvalue,1,5) in ('48502','48503','48504','48505','48506','48507','48529','48532')                        
    and audit1.created >= to_date('04/25/2014', 'MM/DD/YYYY')                                                                   
    and 1 < (                                                                                                                   
            select
                count(audr.id)
            from
                t2 audr
            WHERE
                audr.operationid = audit1.operationid
                and audr.fieldname in ('ADDRESS1','CITY')                                                                       
            )                                                                                                                   

) end auditref,
t1.address1 addr1,
t1.address2 addr2,
t1.city city,
substr(t1.zip,1,5) zip
from
t1
where
t1.id = t1.masterid
and 1 = case
            when substr(t1.zip,1,5) in ('48502','48503','48504','48505','48506','48507','48529','48532') then 1
            when substr(t1.zip,1,5) not in ('48502','48503','48504','48505','48506','48507','48529','48532') and exists                                                                                                         
                                    (select
                                        1
                                    from
                                        t2 audit2
                                    where
                                        audit2.sourceid = t1.id                                                                         
                                        and audit2.fieldname = 'ZIP'
                                        and substr(audit2.oldvalue,1,5) in ('48502','48503','48504','48505','48506','48507','48529','48532')    
                                        and audit2.created >= to_date('04/25/2014', 'MM/DD/YYYY')                                               
                                    ) then 1
            else 0
        end 

任何想法都将不胜感激,因为我尝试过这些连接的任何其他方式都会导致重复行,因为每个 masterid 可能有很多 id。

编辑:

这是查询的更扩展版本,但使用了更多的连接和过滤器,使用 client.id = client.masterid 导致查询运行更慢

问题是限制 t1 和 t2 表扫描的最有效方法,因为这些表很大......

【问题讨论】:

您的查询没有任何意义。请添加示例数据和所需的结果。 问题到底是什么?您是否只需要主 ID 列中显示的那些 ID? 【参考方案1】:

使用以下连接实现了限制表扫描的目标:


from
    client 
        left join client client1 on client1.masterid = client.id and client1.id is null

【讨论】:

以上是关于过滤具有一对多父子映射的表的最有效方法的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate映射关系:一对一对多和多对多

如果同时保存的两个实体父子实体映射为一对多关系,则抛出 id not found 父类异常

Eloquent中一对多关系表的分组和总和

MyBatis之基于XML的表之间映射

映射“一对多”关系的正确方法。在多个实体中具有相同关系时

hibernate映射的 关联关系:有 一对多关联关系,一对一关联关系,多对多关联关系,继承关系