1

I have a table like this:

Items

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 

I would like the select return:

Items

   group   new_object   old_object 

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

If I try:

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;

I have 8 row with many field as null es: last rows:

  group   new_object   old_object 

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

But of group C I want only 2 rows... is not like the other query 'Oracle sql join same table ecc...' because here don't want null result

7
  • 4
    How do you identify that "mars" should be paired with "sun" and "moon" with "earth" and not vice versa in your "C" group? Commented Dec 1, 2015 at 15:26
  • Possible duplicate of Oracle SQL query joining same table Commented Dec 1, 2015 at 15:27
  • mars and moon in the first table have the old_new field set to 'N' that means new so they are under new_object column.. Commented Dec 1, 2015 at 15:30
  • In 'the Oracle SQL query joining same table' the request was there was null rows... here i don't want...so i written compacting... Commented Dec 1, 2015 at 15:35
  • 2
    but why mars-sun in one row, not mars-earth, for example? (that is what is the first question about) Commented Dec 1, 2015 at 15:41

4 Answers 4

1

I'm going to make the assumption that Old and New records are paired in the order they appear based on the ID value. With that assumption the following query:

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;

Aside from the sample data section (with dta) this script first uses the analytic function ROW_NUMBER() to add a sequential number partitioned by the group and old_new columns. It then performs a full outer join on two inline views of the dta2 subfactored query, one for thr old objects and one for the new objects. The result, at least for this data set is:

GRP NEW_OBJECT  OLD_OBJECT
--- ----------  ----------
A   house       pen
B               dog
B               cat
C   mars        sun
C   moon        earth
Sign up to request clarification or add additional context in comments.

3 Comments

but i don't' know the values are in the table... you write: pen, house dog ecc...
@programAll I'm not sure what you mean with your comment. pen, house and dog all came from your problem statement.
yes but are a little example of the date you can find in the DB... in the DB there'll be thousands of rows...
1

In the first step assign an index (IDX) of the chnage withing your group. I'm using order by ID, but this is upon you. The important thing is that the old and new valuea are unique connected with GRP and IDX.

In next step let PIVOT work for you (I'm using the data from @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;

result

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

1 Comment

This answer is based on the same idea as the answer of @Boneist, but my was (idependently) posted 6 mintes later - so if you consider to mark the PIVOT solution as correct answert, pls credit his answer.
0

Here's an alternative using PIVOT to get the results:

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     

Comments

0

Provided that

  • there's at most one new object for each old,
  • there's no new object without old object, and
  • there's at most one old object for any group (this is not true for your sample data, but in comments you indicate you're interested in such solution as well)

a simpler query may be used than for the general case:

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)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.