SQL оракул: получить нулевые значения, когда тип не существует - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть таблица phone с этими значениями

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

Я хочу для каждого emplid свой 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 голосов
/ 15 февраля 2019

Один вариант будет использовать логику с 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

Демо

0 голосов
/ 15 февраля 2019

Попробуйте это

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 
0 голосов
/ 15 февраля 2019

Много версий назад Oracle представила секционированное внешнее объединение только для решения этой проблемы.https://docs.oracle.com/cd/E11882_01/server.112/e25555/tdpdw_sql.htm#TDPDW0072

Вам нужен стол с различными типами, которые необходимо включить.Или, как вы пытались сделать, вы можете создать его на лету.Кроме того, вам нужно предложение "partition" для внешнего соединения.Это показано в ALL CAPS в приведенном ниже коде (чтобы его можно было легко найти).

Как отдельная и не связанная вещь, в подзапросе "helper", который я создаю вместо реальных "типов"В таблице я также создаю столбец ORD, чтобы использовать для упорядочивания.Это необходимо только в том случае, если вы хотите всегда показывать номер HOME перед номером BUSN в основном запросе.Конечно, есть и другие способы достижения того же результата, но, поскольку мы все равно создаем вспомогательный подзапрос, мы получаем его практически без дополнительных затрат.

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          
0 голосов
/ 15 февраля 2019

Вам нужно получить все возможные значения 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', которое вы использовали, даже если это не быловообще нет в ваших данных выборки;но, как вы можете видеть, вы получаете пустые записи для этого имени и для всех идентификаторов сотрудников.

0 голосов
/ 15 февраля 2019

Попробуй вот так.Я думаю, что это похоже на ваш подход

select t.* from Phone t
left outer join 
(
  select 'HOME'as typ from dual
  union select 'HOM2' from dual ) t2
on typ = type
0 голосов
/ 15 февраля 2019

То, что вы пытались, было правильным методом.Просто еще один стол

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...