exists 方法 判断存在,
通常我们会碰到 这种 业务 需求,查询A表中的字段的时候,查询条件涉及到了 B 表中的字段,比如:
A表:
id username password age
1 dd 123 34
2 gg 234 23
3 hh 908 45
4 uu 987 30
。。。
B表
id sex userId
1 男 1
2 女 2
3 男 3
4 男 4
。。。
C表
id role userid
1 经理 1
2 老板 2
3 经理 3
A 表为主表, B表为 子表 外键 userid 与 主表关联,C表为子表 外键为 userid
已有的业务需求:查询 姓名 ,性别, 角色
select a.name ,(select b.sex from B b where b.userid = a.id) sex, (select c.role from C c where c.userid = a.id ) role from A a
我们在公司经常遇到在别人的sql进行修改, 真实的sql 很有可能几百行,很有 可能 会关联很多 表,此时突然加一人需求条件,根据 性别查询,此时 我们首先想到的是,原来的sql 尽量 不要大修改,因为很关关联关系也不是很明白,首先观察到 sex 字段是一个 子查询,在条件中 要按照 sex 进行过滤, 我们在where 后面不能直接 引用 sex 字段,这是也 不能在 from后面追加 B 表, 这时 exists 就可以拍到用场了 ,sql如下:
select a.name ,(select b.sex from B b where b.userid = a.id) sex, (select c.role from C c where c.userid = a.id ) role from A a where exists( select 0 from B b where b.userid = a.id and b.sex ='男')
我们在 实际开发中 很多的 时候 都会 用到 exists 关键字 进行优化sql,
通常情况为 两种: 一种是 select中 有子查询 加入 输出字段为 zcx , 并且在 在 条件中需要这个 字段进行判断, 这时我们可以 利用exists 进行过滤。这时很巧妙的。
第二种是: sql 进行优化的时候,两张表的 数据太大,本人在实际的开发中实际的编写sql 中 有两 张 表,我记得一张表为 一亿多的数据 ,这里七个别名 为 A ,另一张表为 6千万的数据,这里七个别名 为 B ,而 B表需要先查询一次, 并且按照外键 和A 表进行关联, 然后将查询的结果 看作另一张表,再和A表关联, 好啦逻辑有点复杂 直接把sql 贴出来:
with cbizvivew as(
(select min(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_WAIT',
cbiz_event_time,
null)) as firstwait, ---第一次等待时间 用于前端判断条件
min(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_ACCEPT',
cbiz_event_time,
null)) as firstaccpt, ----第一次确认时间 用于前端判断条件
min(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_REJECT',
cbiz_event_time,
null)) as firstreject, ----第一次拒绝时间 用于前端判断条件
min(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_WAIT',
cbiz_event_time,
'FFOP_UME_WEB_SHIPPING_ACCEPT',
cbiz_event_time,
'FFOP_UME_WEB_SHIPPING_REJECT',
cbiz_event_time,
null)) as minbktime, ----第一次设置订舱状态时间
min(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_WAIT',
CBIZ_ID,
'FFOP_UME_WEB_SHIPPING_ACCEPT',
CBIZ_ID,
'FFOP_UME_WEB_SHIPPING_REJECT',
CBIZ_ID,
null)) as minid, ----第一次设置订舱状态时间
max(cbiz_event_time) as fourEvntFirstTime, ---4个事件中最新的那个时间
max(decode(cbiz_event,
'EWEB_ORDER_CHANGED',
cbiz_event_time,
null)) as endoc, -----最新的一次订舱修改的时间
max(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_WAIT',
cbiz_event_time,
null)) as endwait, ---最新的一次等待时间
max(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_ACCEPT',
cbiz_event_time,
null)) as endaccpt, ----最新的一次确认时间
max(decode(cbiz_event,
'FFOP_UME_WEB_SHIPPING_REJECT',
cbiz_event_time,
null)) as endreject, ---最新的一次拒绝时间
cbiz_consign_id as cbiz_consign_id --- 运编号
from cbiztrace a
where a.cbiz_org_id = '83'
and a.cbiz_event in ('FFOP_UME_WEB_SHIPPING_ACCEPT',
'FFOP_UME_WEB_SHIPPING_WAIT',
'FFOP_UME_WEB_SHIPPING_REJECT',
'EWEB_ORDER_CHANGED')
and exists
(Select 1
from fconsign fcsg
where fcsg.FCSG_ORG_ID = '83'
and a.cbiz_consign_id = fcsg.FCSG_CONSIGN_ID
and fcsg.FCSG_ETD> to_date('2018-07-17 18:10:05','yyyy-mm-dd hh24:mi:ss') -- E T D
and fcsg.FCSG_ETD< to_date('2018-08-17 18:10:05','yyyy-mm-dd hh24:mi:ss')
and fcsg.FCSG_CREATE_TIME > to_date('2018-07-17 18:10:05','yyyy-mm-dd hh24:mi:ss') --创建日期
and fcsg.FCSG_CREATE_TIME< to_date('2018-08-17 18:10:05','yyyy-mm-dd hh24:mi:ss')
/*and fcsg.fcsg_vessel_en = 'KOTA PERDANA' --船名航次
and fcsg.fcsg_voyage_en = '0003E'*/
)
group by cbiz_consign_id)
)
select
cbiz.firstaccpt, cbiz.firstwait ,cbiz.firstreject,
FCSG_CONSIGN_ID, --- 运编号
FCSG_BO_NO, --- 提单号 MB/ L NO 1
FCSG_BOOKING_AGENT, --- 订舱代理代码,对应前台的舱位公司 2
FCSG_VESSEL_EN, --- 英文船名 3
FCSG_ETD, --- 船期 预离日期(出口)或到港日期(进口) 4
FCSG_CUST_CSG_NO, --- 客户业务号 5
FCSG_CONSIGN_DEPT, -- 委托单位 客户供应商行信息编号,类型为客户 6
FCSG_PAYMODE_ID, --- 付款方式 7
FCSG_TERM_ID, --- 运输条款 8
FCSG_BOK_CONTRACT_NO, --- 订舱协议号 9
FCSG_VOYAGE_EN, --- 航次 10
FCSG_SHIPPING_LINE_TRADE, --- 船公司航线 11
---rst.CACC_BL_CUT_TIME, --- 提单截单时间 12
FCSG_DISCHARGE_PORT_CODE, --- 卸货港 13
FCSG_DELIVERY_PLACE_CODE, --- 交货地 14
hy_ff_utility_pkg.F_GET_CONSIGN_CNT_TYPE_QTY(fcsg.FCSG_CONSIGN_ID,
1) ctcn, ---FCTP_CNT_TYPE ||'*'|| FCTP_CNT_COUNT 箱型箱量 15
FCSG_CONTACTOR, --- 客户联系人 16
FCSG_CONSIGN_TYPE, --- 托运类型 17
(select FCCI_IS_DANGER
from fconsigncargoinfo fio
where fio.FCCI_CONSIGN_ID = fcsg.FCSG_CONSIGN_ID
and fio.FCCI_TYPE = 1
and rownum = 1) as FCCI_IS_DANGER, --- 是否危险品 18
(select FCTP_IS_SOC
from fcontainerprepare fp
where fp.FCTP_CONSIGN_ID = fcsg.FCSG_CONSIGN_ID
and rownum = 1) issoc, --- 是否SOC箱 19
FCSG_REMARK, --- 订舱备注 20
FCSG_CREATE_TIME, --- 创建时间 21
cbiz.minbktime AS first_one_set_time, --- 第 一次设置订舱状态时间 22
(select CREATOR
from cbiztrace cb
where cb.CBIZ_ID = cbiz.minid
and rownum = 1) AS CREATOR, ---创建人 23
---当创建时间≤15:00,且第一次设置订舱状态的日期=创建日期,则判定为Y
---当创建时间>15:00,且第一次设置订舱状态的日期=创建日期+1个工作日,则判定为Y
---当创建时间≤15:00,且第一次设置订舱状态的日期>创建日期,则判定为N
---当创建时间>15:00,且第一次设置订舱状态的日期>创建日期+1个工作日,则判定为N
(case
when to_char(FCSG_CREATE_TIME, 'hh24:mi:ss') <= '15:00' and
to_char(cbiz.minbktime, 'yyyy-mm-dd') =
to_char(FCSG_CREATE_TIME, 'yyyy-mm-dd') then
'Y'
when to_char(FCSG_CREATE_TIME, 'hh24:mi:ss') > '15:00' and
to_char(cbiz.minbktime, 'yyyy-mm-dd') =
to_char(FCSG_CREATE_TIME + 1, 'yyyy-mm-dd') then
'Y'
when to_char(FCSG_CREATE_TIME, 'hh24:mi:ss') <= '15:00' and
to_char(cbiz.minbktime, 'yyyy-mm-dd') >
to_char(FCSG_CREATE_TIME, 'yyyy-mm-dd') then
'N'
when to_char(FCSG_CREATE_TIME, 'hh24:mi:ss') > '15:00' and
to_char(cbiz.minbktime, 'yyyy-mm-dd') >
to_char(FCSG_CREATE_TIME + 1, 'yyyy-mm-dd') then
'N'
else
' '
end) WHETHER_FINAL_STATE_COMPLETED, ---是否在规定时间内完成状态设置 24
(case cbiz.fourEvntFirstTime
when cbiz.endaccpt then
'订舱确认'
when cbiz.endwait then
'订舱等待'
when cbiz.endreject then
'订舱失败'
when cbiz.endoc then
'订舱修改'
else
' '
end) AS FINALS_STATE --- 最终状态25
from FCONSIGN fcsg,cbizvivew cbiz
where cbiz.cbiz_consign_id = fcsg.FCSG_CONSIGN_ID
/*and cbiz.firstaccpt > to_date('2015-07-17 18:10:05','yyyy-mm-dd hh24:mi:ss') --订舱确认
and cbiz.firstaccpt < to_date('2018-08-17 18:10:05','yyyy-mm-dd hh24:mi:ss')
*/
/* and cbiz.firstwait > to_date('2015-07-17 18:10:05','yyyy-mm-dd hh24:mi:ss') --订舱等待
and cbiz.firstwait < to_date('2015-08-17 18:10:05','yyyy-mm-dd hh24:mi:ss')
and cbiz.firstreject > to_date('2015-07-17 18:10:05','yyyy-mm-dd hh24:mi:ss') --订舱失败
and cbiz.firstreject < to_date('2015-08-17 18:10:05','yyyy-mm-dd hh24:mi:ss')*/
大家注意 : 红色的 查询条件 被注释掉, 然后在蓝色的地方进行 使用exists 进行过滤,这里我们可以 知道 先用exists 进行过滤 掉一定的数据,并且是按照索引 ,效率 是非常的高的。而红色的地方,则在 cbizvivew 中会 进行全表扫描,这样的效率是 非常慢的。 所以 我们在 sql 中 要学会 用exists 进行优化。。。。。。。。。