两个表都有数据

时间:2018-03-21 06:40:52

标签: sql oracle

我正在进行一个简单的查询,我将从两个表中显示数据。条件是如果alloment表有数据并且leave详细信息没有数据,那么它应该仅显示分配表中的数据。就我而言,当两个表都有数据时,它会显示数据。试过这个但是当两个表都有数据时返回:

SELECT K.EMPNO, K.LV_NAME, K.ALLOTMENT, K.REMAIN, M.LV_FROM, M.LV_TO
FROM  LV_ADJ_DETAILS m
LEFT JOIN TBL_LV_ALLOTMENT k 
    ON M.EMPNO = K.EMPNO
WHERE K.EMPNO = 'EMP00259'
  AND K.YEAR_NAME = '2018'
  AND EXTRACT(YEAR FROM M.LV_TO) = '2018';

预期产出: 2018年

如果两个表都有数据 -

EMPNO       LV_NAME             ALLOTMENT REMAIN   LV_FROM        LV_TO
EMP00259    MLWP                    0      0      4/22/2018     4/30/2018           
EMP00259    Maternity Leave        103    103     5/20/2018     5/22/2018
EMP00259    MLWP                    0      0      5/24/2018     5/26/2018
EMP00259    Maternity Leave        103    103     5/28/2018     5/30/2018

如果一个表有数据 - 如果没有留下详细信息,例如离开和到

EMPNO           LV_NAME             ALLOTMENT REMAIN LV_FROM        LV_TO
EMP00259        MLWP                    0       0           
EMP00259        Maternity Leave 103    103     103

脚本

CREATE TABLE HRD.TBL_LV_ALLOTMENT
(
  EMPNO      VARCHAR2(10 BYTE),
  LV_NAME    VARCHAR2(30 BYTE),
  YEAR_NAME  INTEGER,
  ALLOTMENT  NUMBER,
  ENJOY      NUMBER,
  REMAIN     NUMBER,
  STATUS     INTEGER
)

CREATE TABLE HRD.LV_ADJ_DETAILS
(
  EMPNO       VARCHAR2(20 BYTE),
  APP_NO      VARCHAR2(10 BYTE),
  LEAVE_NAME  VARCHAR2(30 BYTE),
  APV_DAYS    NUMBER(3),
  LV_FROM     DATE,
  LV_TO       DATE,
  BALANCE     NUMBER(3),
  COM_ID      VARCHAR2(15 BYTE)
)

注意:我在WHERE子句中使用年份进行过滤。

3 个答案:

答案 0 :(得分:3)

外连接的第一件事是使表顺序正确。使用LEFT OUTER JOIN,包含所有表的表在连接之前出现,并且表中包含一些表。你说......

  

如果alloment表有数据并且请假详细信息没有数据,那么它应该只显示分配表中的数据

...所以正确的连接顺序是tbl_lv_allotment k left outer join lv_adj_details m

在外连接中进行过滤时,还有一个陷阱,你已经成为它的牺牲品。通过在WHERE子句标准中包含m.lv_to,您将丢弃m.lv_to为空的任何行,这会使外连接短路。有几种方法可以解决这个问题,但最简单的方法是测试null:

select k.empno
        , k.lv_name 
        , k.allotment
        , k.remain
        , m.lv_from
        , m.lv_to
from  tbl_lv_allotment k 
      left outer join lv_adj_details m
           on m.empno = k.empno
where k.empno = 'EMP00259'
and k.year_name = '2018'
and ( m.lv_to is null or extract(year from m.lv_to) = '2018' );

但是,根据您的数据,使用子查询可能更好:

select k.empno
        , k.lv_name 
        , k.allotment
        , k.remain
        , m.lv_from
        , m.lv_to
from  tbl_lv_allotment k 
    left outer join ( select * from lv_adj_details
                       where extract(year from lv_to) = '2018' ) m
    on m.empno = k.empno
where k.empno = 'EMP00259'
  and k.year_name = '2018'
  ;

以下是使用查询版本的a demo on SQL Fiddle,显示了WHERE子句如何颠覆外部联接。

在小提琴中,我改变了连接标准以包含and m.leave_name = k.lv_name。这将删除从一个表中的所有行与另一个表中的所有行匹配所得到的可怕产品。我在这里没有这样做,因为我认为答案中的代码应该产生问题中显示的输出。

答案 1 :(得分:2)

您希望从表格Error while requesting the database « -- » : invalid command name "parray" 中选择,并从表格tbl_lv_allotment中选择外部联接记录,但反之亦然。

然后想象主表在外连接表中没有匹配的情况。然后得到一行,外连接表的所有列都为null。如果您在该表的lv_adj_details子句中有条件(例如查询中的WHERE),则立即关闭该行,因为在外部连接行中此值为null。这使您的外部联接仅仅是内部联接。外连接表的标准属于K.EMPNO = 'EMP00259'子句:

ON

我已将select a.empno, a.lv_name, a.allotment, a.remain, d.lv_from, d.lv_to from tbl_lv_allotment a left join lv_adj_details d on d.empno = a.empno and to_char(d.lv_to, 'yyyy') = a.year_name where a.empno = 'EMP00259' and a.year_name = '2018'; (应该是EXTRACT(YEAR FROM M.LV_TO) = '2018',而不是2018,因为您正在处理此处的数字)更改为'2018',因为很明显这是关于匹配的主表年。

答案 2 :(得分:1)

where子句中的这个条件(AND EXTRACT(YEAR FROM M.LV_TO) = '2018')会产生问题。

试试这个:

SELECT K.EMPNO, K.LV_NAME, K.ALLOTMENT, K.REMAIN, M.LV_FROM, M.LV_TO 
FROM  LV_ADJ_DETAILS m 
LEFT JOIN TBL_LV_ALLOTMENT k 
    ON M.EMPNO = K.EMPNO AND EXTRACT(YEAR FROM M.LV_TO) = '2018'
WHERE K.EMPNO = 'EMP00259' AND K.YEAR_NAME = '2018';