简体   繁体   中英

Comparing two columns in a same table by considering the duplicates

I have a sample table as follows.

A      B               C         D
------+---------+--------+---------
3.2   |  India  |  456   |  3.2
3.2   |  India  |  -67   |  5
-3.2  |  US     |  -30   |  8
3.2   |  UK     |  3.9   |  5
5     |  UAE    |  2.4   |  9
6     |  UAE    |  5     |  -3.2

I would like to first sort the data as shown in the below format. 'B' & 'C' columns are tied to 'D' column such that when I sort 'D' then 'B' & 'C' columns will move accordingly. But 'A' is independent

A(ascending)   B           C       D((Descending))
------------+-----------+--------+--------
-3.2        |   UAE     |   2.4  |  9
3.2         |   US      |  -30   |  8
3.2         |   India   |  -67   |  5
3.2         |   UK      |  3.9   |  5
5           |   India   |  456   |  3.2
6           |   UAE     |  5     |  -3.2

For the table above I would like to get the following as final output (I am ignoring the signs while comparing). In the above table I am Checking 'D' column value in 'A' column(One to One mapping) if it is not their then it should push it down

A(ascending)   B           C       D((Descending))
------------+-----------+--------+--------
-3.2        |   India   |  456   |  3.2
3.2         |   UAE     |  5     |  -3.2
3.2         |   null    |  null  |  null
3.2         |   null    |  null  |  null
5           |   India   |  -67   |  5
6           |   null    |  null  |  null 
null        |   UAE     |   2.4  |  9
null        |   US      |  -30   |  8
null        |   UK      |  3.9   |  5

FINAL OUTPUT (Values which are pushed down):

null        |   UAE     |   2.4  |  9
null        |   US      |  -30   |  8
null        |   UK      |  3.9   |  5

It's probably using NOT IN , COUNT and a JOIN but I can't seem to put it together properly (especially since I'm selecting data from the same table). Does any one have an idea about this? Thanks.

The following is a total guess, because there isn't enough information in your question to fully understand the join between the a and d columns that you're expecting. I've taken my best guess at it, but if the following is not correct, you'll either have to amend it as appropriate for your logic, or update your question with the correct logic.

with sample_data as (select 3.2 a, 'India' b, 456 c, 3.2 d from dual union all
                     select 3.2 a, 'India' b, -67 c, 5 d from dual union all
                     select -3.2 a, 'US' b, -30 c, 8 d from dual union all
                     select 3.2 a, 'UK' b, 3.9 c, 5 d from dual union all
                     select 5 a, 'UAE' b, 2.4 c, 9 d from dual union all
                     select 6 a, 'UAE' b, 5 c, -3.2 d from dual),
-- end of the "sample_data" subquery mimicking your table with data in it
             sd1 as (select row_number() over (order by a) rn,
                            a
                     from   sample_data),
             sd2 as (select row_number() over (order by d desc, b, c) rn,
                            b,
                            c,
                            d
                     from   sample_data),
             sd3 as (select sd1.a,
                            sd2.b,
                            sd2.c,
                            sd2.d
                     from   sd1
                            inner join sd2 on (sd1.rn = sd2.rn))
select case when sd5.a is not null and sd4.a is not null then sd4.a
            when sd5.a is not null then null
            else sd4.a
       end a,
       case when sd5.b is not null and row_number() over (partition by sd5.a, sd5.b, sd5.c, sd5.d order by sd4.d desc) = 1 then sd5.b
            else null
       end b,
       case when sd5.c is not null and row_number() over (partition by sd5.a, sd5.b, sd5.c, sd5.d order by sd4.d desc) = 1 then sd5.c
            else null
       end c,
       case when sd5.d is not null and row_number() over (partition by sd5.a, sd5.b, sd5.c, sd5.d order by sd4.d desc) = 1 then sd5.d
            else null
       end d
from   sd3 sd4
       full outer join sd3 sd5 on (sd4.a = sd5.d)
order by case when a is not null then 1 else 2 end,
         a;

         A B              C          D
---------- ----- ---------- ----------
      -3.2 UAE            5       -3.2
       3.2 India        456        3.2
       3.2                            
       3.2                            
         5 UK           3.9          5
         5 India        -67          5
         6                            
           UAE          2.4          9
           US           -30          8

After the additional information you provided, how about something like:

with sample_data as (select 3.2 a, 'India' b, 456 c, 3.2 d from dual union all
                     select 3.2 a, 'India' b, -67 c, 5 d from dual union all
                     select -3.2 a, 'US' b, -30 c, 8 d from dual union all
                     select 3.2 a, 'UK' b, 3.9 c, 5 d from dual union all
                     select 5 a, 'UAE' b, 2.4 c, 9 d from dual union all
                     select 6 a, 'UAE' b, 5 c, -3.2 d from dual),
-- end of the "sample_data" subquery mimicking your table with data in it
             sd1 as (select row_number() over (order by a) rn,
                            a
                     from   sample_data),
             sd2 as (select row_number() over (order by d desc, b, c) rn,
                            b,
                            c,
                            d
                     from   sample_data),
             sd3 as (select sd1.a,
                            sd2.b,
                            sd2.c,
                            sd2.d,
                            row_number() over (partition by sd2.d order by sd1.a) rnd,
                            row_number() over (partition by sd1.a order by sd2.d) rna
                     from   sd1
                            inner join sd2 on (sd1.rn = sd2.rn))
select case when sd5.a is not null and sd4.a is not null then sd4.a
            when sd5.a is not null then null
            else sd4.a
       end a,
       case when sd5.b is not null then sd5.b
            else null
       end b,
       case when sd5.c is not null then sd5.c
            else null
       end c,
       case when sd5.d is not null then sd5.d
            else null
       end d
from   sd3 sd4
       full outer join sd3 sd5 on (sd4.a = sd5.d and sd4.rna = sd5.rnd)
order by case when a is not null then 1 else 2 end,
         a,
         d;

         A B              C          D
---------- ----- ---------- ----------
      -3.2 UAE            5       -3.2
       3.2 India        456        3.2
       3.2                            
       3.2                            
         5 India        -67          5
         6                            
           UK           3.9          5
           US           -30          8
           UAE          2.4          9

Depending on whether you really don't care about the sign of the values in the a and d columns, you may wish to use abs() in all the relevant places in the above query.

Also, storing values in a column that aren't related to the rest of the row is usually indicative of bad design. Why is your data stored like that?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM