2015-12-01 5 views
1

У меня есть таблица вроде этого:Oracle SQL запрос с использованием случай, когда, уплотняя нулевые поля

Предметы

id  group old_new  object 

1   A   O   pen 
2   A   N   house 
3   B   O   dog 
4   B   O   cat 
5   C   N   mars 
6   C   O   sun 
7   C   N   moon 
8   C   o   earth 

Я хотел бы, выберите возвращение:

товары

group new_object old_object 

    A  house  pen  
    B  null  dog 
    B  null  cat 
    C  mars  sun 
    C  moon  earth 

Если я попробую:

select id, 
     case when old_new = 'N' then object end as new_object, 
     case when old_new = 'O' then object end as old_object 
from the_table 
order by id; 

У меня есть 8 ряда со многими полями как нулевые эсов: последние строки:

group new_object old_object 

    C  mars  null 
    c  null  sun 
    C  moon  null 
    c  null  earth 

Но групп CI хотят только 2 строки ... не нравятся другой запрос «Oracle SQL присоединиться к тому же таблицам ЕСС ...», потому что здесь не хочу нулевой результат

+4

Как определить, что «Марс» должны быть в паре с «солнце» и «луна» с «землей», а не наоборот в группе «C»? –

+0

Возможный дубликат [Oracle SQL query, соединяющий ту же таблицу] (http://stackoverflow.com/questions/34020184/oracle-sql-query-joining-same-table) – davegreen100

+0

Марс и луна в первой таблице имеют набор old_new к «N», что означает новый, так что они находятся под столбцом new_object .. – programAll

ответ

0

при условии, что

  • есть максимум один новый объект для каждого старого,
  • нет нового объекта без старого объекта, и
  • Существует не более одного старого объекта для любой группы (это не истинно для ваших данных образца, но в комментариях вы также указываете, что вас интересует такое решение)

более простой запрос может быть использован, чем для общего случая:

select 
    old.group as group, new.object as new_object, old.object as old_object 
from 
    (select group, object from my_table where old_new = 'O') old 
     left join 
    (select group, object from my_table where old_new = 'N') new 
     on (old.group = new.group) 
1

Я собираюсь сделать предположение о том, что старые и новые записи спаренный в порядке, они появляются на основании значения ID , При этом предположении следующего запроса:

WITH DTA(ID, GRP, OLD_NEW, OBJECT) AS (
    select 1, 'A', 'O', 'pen' from dual union all 
    select 2, 'A', 'N', 'house' from dual union all 
    select 3, 'B', 'O', 'dog' from dual union all 
    select 4, 'B', 'O', 'cat' from dual union all 
    select 5, 'C', 'N', 'mars' from dual union all 
    select 6, 'C', 'O', 'sun' from dual union all 
    select 7, 'C', 'N', 'moon' from dual union all 
    select 8, 'C', 'O', 'earth' from dual 
), dta2 as (
select dta.* 
    , row_number() over (partition by GRP, old_new order by id) rn 
    from dta 
) 
select coalesce(n.grp, o.grp) grp 
    , n.object new_object 
    , o.object old_object 
    from (select * from dta2 where old_new = 'N') n 
    full join (select * from dta2 where old_new = 'O') o 
    on n.grp = o.grp 
    and n.rn = o.rn; 

Помимо секции выборки данных (with dta) этот сценарий первым использует аналитическую функцию ROW_NUMBER(), чтобы добавить порядковый номер, разделенный группой и old_new колонн. Затем он выполняет полное внешнее соединение на двух встроенных представлениях субфакторированного запроса dta2, один для старых объектов и один для новых объектов. В результате, по крайней мере, для этого набора данных:

GRP NEW_OBJECT OLD_OBJECT 
--- ---------- ---------- 
A house  pen 
B    dog 
B    cat 
C mars  sun 
C moon  earth 
+0

, но я не знаю, что значения находятся в таблице ... вы пишете: pen, house dog ecc ... – programAll

+0

@programAll I ' m не уверен, что вы имеете в виду с вашим комментарием. ручка, дом и собака все пришли из вашего заявления о проблеме. – Sentinel

+0

да, но это небольшой пример даты, которую вы можете найти в БД ... в БД будет тысячи строк ... – programAll

0

Вот альтернатива использования PIVOT, чтобы получить результаты:

with items as (select 1 id, 'A' grp, 'O' old_new, 'pen' obj from dual union all 
       select 2 id, 'A' grp, 'N' old_new, 'house' obj from dual union all 
       select 3 id, 'B' grp, 'O' old_new, 'dog' obj from dual union all 
       select 4 id, 'B' grp, 'O' old_new, 'cat' obj from dual union all 
       select 5 id, 'C' grp, 'N' old_new, 'mars' obj from dual union all 
       select 6 id, 'C' grp, 'O' old_new, 'sun' obj from dual union all 
       select 7 id, 'C' grp, 'N' old_new, 'moon' obj from dual union all 
       select 8 id, 'C' grp, 'O' old_new, 'earth' obj from dual) 
-- end of mimicking your items table with data in it. See SQL below: 
select grp, 
     new_object, 
     old_object 
from (select grp, 
       old_new, 
       obj, 
       row_number() over (partition by grp, old_new order by id) rn 
     from items) 
pivot (max(obj) 
     for old_new in ('N' new_object, 
           'O' old_object)) 
order by grp, 
     rn; 

GRP NEW_OBJECT OLD_OBJECT 
--- ---------- ---------- 
A house  pen  
B    dog  
B    cat  
C mars  sun  
C moon  earth  
1

На первом шаге назначить индекс (IDX) в chnage жгутов ваш группа. Я использую порядок по ID, но это на вас. Важно то, что старые и новые значения являются уникальными, связанными с GRP и IDX.

В следующем шаге пусть PIVOT работает на вас (я использую данные из @Sentinel, thx!)

WITH DTA(ID, GRP, OLD_NEW, OBJECT) AS (
    select 1, 'A', 'O', 'pen' from dual union all 
    select 2, 'A', 'N', 'house' from dual union all 
    select 3, 'B', 'O', 'dog' from dual union all 
    select 4, 'B', 'O', 'cat' from dual union all 
    select 5, 'C', 'N', 'mars' from dual union all 
    select 6, 'C', 'O', 'sun' from dual union all 
    select 7, 'C', 'N', 'moon' from dual union all 
    select 8, 'C', 'O', 'earth' from dual 
), DTA2 as (
SELECT 
ROW_NUMBER() OVER (PARTITION BY GRP,OLD_NEW order by ID) as IDX, 
GRP, OLD_NEW, OBJECT 
from DTA 
) 
select * from DTA2 
PIVOT (max(OBJECT) OBJECT for (OLD_NEW) in 
('N' as "NEW", 
'O' as "OLD" 
)) 
order by GRP; 

результат

IDX, GRP, NEW_OBJECT, OLD_OBJECT 
1 A house pen 
1 B   dog 
2 B   cat 
2 C moon earth 
1 C mars sun 
+0

Этот ответ основан на той же идее, что и ответ @Boneist, но мой был (по-видимому) отправлен 6 месяцев спустя, поэтому, если вы считаете, что решение PIVOT является правильным, ответьте на его ответ. –

Смежные вопросы