Home > Software engineering >  ORACLE SELECT DISTINCT VALUE ONLY IN SOME COLUMNS
ORACLE SELECT DISTINCT VALUE ONLY IN SOME COLUMNS

Time:11-20

     ---- ------ ------- --------- --------- 
    | id | order| value | type    | account | 
     ---- ------ ------- --------- --------- 
    |  1 | 1    |     a |       2 |    1    |
    |  1 | 2    |     b |       1 |    1    |
    |  1 | 3    |     c |       4 |    1    |
    |  1 | 4    |     d |       2 |    1    |
    |  1 | 5    |     e |       1 |    1    |
    |  1 | 5    |     f |       6 |    1    |
    |  2 | 6    |     g |       1 |    1    |
     ---- ------ ------- --------- --------- 

I need get a select of all fields of this table but only getting 1 row for each combination of id type (I don't care the value of the type). But I tried some approach without result.

At the moment that I make an DISTINCT I cant include rest of the fields to make it available in a subquery. If I add ROWNUM in the subquery all rows will be different making this not working.

Some ideas?

My better query at the moment is this:

SELECT ID, TYPE, VALUE, ACCOUNT
FROM MYTABLE
WHERE ROWID IN (SELECT DISTINCT MAX(ROWID)    
                FROM MYTABLE
                GROUP BY ID, TYPE);

CodePudding user response:

It seems you need to select one (random) row for each distinct combination of id and type. If so, you could do that efficiently using the row_number analytic function. Something like this:

select id, type, value, account
from   (
         select id, type, value, account, 
                row_number() over (partition by id, type order by null) as rn
         from   your_table
       )
where  rn = 1
;

order by null means random ordering of rows within each group (partition) by (id, type); this means that the ordering step, which is usually time-consuming, will be trivial in this case. Also, Oracle optimizes such queries (for the filter rn = 1).

Or, in versions 12.1 and higher, you can get the same with the match_recognize clause:

select id, type, value, account
from   my_table
match_recognize (
  partition by id, type
  all rows  per match
  pattern   (^r)
  define    r as null is null
);

This partitions the rows by id and type, it doesn't order them (which means random ordering), and selects just the "first" row from each partition. Note that some analytic functions, including row_number(), require an order by clause (even when we don't care about the ordering) - order by null is customary, but it can't be left out completely. By contrast, in match_recognize you can leave out the order by clause (the default is "random order"). On the other hand, you can't leave out the define clause, even if it imposes no conditions whatsoever. Why Oracle doesn't use a default for that clause too, only Oracle knows.

  • Related