sql oracle:在类型不存在时获取空值

时间:2019-02-15 14:26:29

标签: sql oracle

我有一个带有这些值的表phone

emplid  type    phone
1       HOME    23452
2       HOME    15284
2       BUSN    25523
3       HOME    26542

我想让每个人都使用他的HOME和BUSN电话。如果他没有BUSN电话,则必须为空。所以我的结果必须是:

emplid  type    phone
1       HOME    23452
2       HOME    15284
2       BUSN    25523
3       HOME    26542
1       BUSN    null
3       BUSN    null

我试图加入一个虚拟表

(select 'HOME'as typ from dual
                union select 'HOM2' from dual )

但是它没有给我想要的结果。我不知道如何将其与我的phone表一起加入

6 个答案:

答案 0 :(得分:5)

许多版本以前,Oracle仅为这种问题引入了分区外连接。 https://docs.oracle.com/cd/E11882_01/server.112/e25555/tdpdw_sql.htm#TDPDW0072

您确实需要一个包含各种类型的表。或者,您可以尝试动态创建它。另外,您需要外部联接的“ partition”子句。该代码显示在下面代码的ALL CAPS中(因此可以轻松找到它)。

作为单独的,不相关的内容,在我创建的“ helper”子查询中,它代替了实际的“类型”表,我还创建了一个ORD列,用于排序。仅当您要始终在主查询中的BUSN编号之前始终显示HOME编号时才需要这样做。当然,还有其他方法可以达到相同的结果,但是由于无论如何我们都创建了一个辅助子查询,因此基本上不需要额外的费用就可以得到它。

with
  phone(emplid, type, phone) as (
    select 1, 'HOME', 23452 from dual union all
    select 2, 'HOME', 15284 from dual union all
    select 2, 'BUSN', 25523 from dual union all
    select 3, 'HOME', 26542 from dual
  )
-- end of sample data (for testing only, not part of the actual query)
select p.emplid, h.type, p.phone
from   (
         select 'HOME' as type, 1 as ord from dual union all
         select 'BUSN'        , 2        from dual
       ) h
       left outer join phone p  PARTITION BY (EMPLID)
       on h.type = p.type
order by p.emplid, h.ord     
;

    EMPLID TYPE      PHONE
---------- ---- ----------
         1 HOME      23452
         1 BUSN           
         2 HOME      15284
         2 BUSN      25523
         3 HOME      26542
         3 BUSN          

答案 1 :(得分:1)

您需要获取所有可能的emplid值并与所有可能的type值交叉联接,然后使用外部联接查看实际存在的那些。

例如,如果您希望完全基于phone表中的其他数据,则可以使用内联视图获得前两列的不同值:

-- CTE for your sample data
with phone (emplid, type, phone) as (
  select 1, 'HOME', 23452 from dual
  union all select 2, 'HOME', 15284 from dual
  union all select 2, 'BUSN', 25523 from dual
  union all select 3, 'HOME', 26542 from dual
)
-- actual query
select e.emplid, t.type, p.phone
from (select distinct emplid from phone) e
cross join (select distinct type from phone) t
left join phone p on p.emplid = e.emplid and p.type = t.type;

    EMPLID TYPE      PHONE
---------- ---- ----------
         1 HOME      23452
         2 HOME      15284
         2 BUSN      25523
         3 HOME      26542
         3 BUSN           
         1 BUSN           

但是您可能真的想从一个雇员表中获取可能的emplid值-在这种情况下,即使他们根本没有电话记录,您也会看到所有雇员的空值;并且您可能想从其他表中获取可能的type值,或对列表进行硬编码:

select e.emplid, t.type, p.phone
from (select distinct emplid from phone) e -- or more likely from a separate employee table
cross join (select 'HOME' as type from dual union all select 'HOM2' from dual) t
left join phone p on p.emplid = e.emplid and p.type = t.type;

    EMPLID TYPE      PHONE
---------- ---- ----------
         1 HOME      23452
         2 HOME      15284
         3 HOME      26542
         1 HOM2           
         2 HOM2           
         3 HOM2           

即使您的样本数据中根本没有使用'HOM2'值,我仍然坚持使用;但是如您所见,您也会在所有员工ID的名称中得到空条目。

答案 2 :(得分:0)

您尝试的是正确的方法。只是另一张桌子

SELECT PhoneTypes.EmplID, PhoneTypes.Type, Phone
FROM Phone
RIGHT OUTER JOIN (SELECT Distinct emplid, T.Type FROM Phone, (select 'HOME' FROM DUAL as type union select 'HOM2' FROM DUAL union select 'BUSN' FROM DUAL) T) PhoneTypes
   ON Phone.type=PhoneTypes.Type

答案 3 :(得分:0)

尝试这样。我认为这与您的方法类似

select t.* from Phone t
left outer join 
(
  select 'HOME'as typ from dual
  union select 'HOM2' from dual ) t2
on typ = type

答案 4 :(得分:0)

尝试一下

with 
phone as (
    select 1 as emplid, 'HOME' as type, '23452' as phone from dual union
    select 2, 'HOME', '15284' from dual union
    select 2,'BUSN','25523' from dual union
    select 3,'HOME','26542' from dual),
types as (
    select distinct type from phone 
    )
select phone.emplid, types.type, phone.phone 
 from types
  left join phone partition by (emplid)
      on phone.type = types.type 

答案 5 :(得分:0)

一种选择是将逻辑与not in

一起使用
with phone(emplid, type, phone) as 
(
 select 1, 'HOME', 23452 from dual union all
 select 2, 'HOME', 15284 from dual union all
 select 2, 'BUSN', 25523 from dual union all
 select 3, 'HOME', 26542 from dual
)
select * from phone
union all
select emplid, 'BUSN', null 
  from phone
 where emplid not in 
       ( select emplid 
           from phone p 
          where type = 'BUSN'
            and p.emplid = emplid );

EMPLID  TYPE    PHONE
------  ----    -----
1       HOME    23452
2       HOME    15284
2       BUSN    25523
3       HOME    26542
3       BUSN    NULL
1       BUSN    NULL

Demo