Есть ли способ условно установить значение агрегата в Oracle 12c? - PullRequest
1 голос
/ 19 сентября 2019

Я хочу настроить запрос, который бы заполнял столбец из запроса GROUP BY на основе того, имеет ли поле заданное значение в группе.Я работаю в Oracle 12c.

Пример таблицы:

uname    event   tstamp
------  ------  ----------------------
user1   3       10-SEP-19 11.00.00 AM
user1   9       14-SEP-19 11.00.00 AM
user1   32       14-AUG-19 11.00.00 AM
user1   21      20-AUG-19 11.00.00 AM
user1   8       23-AUG-19 11.00.00 AM
user2   9       14-AUG-19 11.00.00 AM
user2   8       23-AUG-19 11.00.00 AM
user2   3       05-SEP-19 11.00.00 AM
user3   15      06-AUG-19 11.00.00 AM
user3   1       30-AUG-19 11.00.00 AM
user3   7       14-SEP-19 11.00.00 AM

Я хотел бы запрос на вывод:

uname    event   tstamp
------  ------  ---------------------
user1   21      14-SEP-19 11.00.00 AM
user2   8       05-SEP-19 11.00.00 AM
user3   7       14-SEP-19 11.00.00 AM

Я искал запрос, которыйсработало примерно так:

select uname, SomeAggregate(if contains 21 then 21 else DoesNotMatter) event, max(tstamp)
from table
group by uname

Ответы [ 4 ]

2 голосов
/ 19 сентября 2019

Как насчет этого?

SQL> with test (uname, event, tstamp) as
  2    (select 'user1', 3,  date '2019-09-10' from dual union all
  3     select 'user1', 9,  date '2019-09-14' from dual union all
  4     select 'user1', 32, date '2019-08-14' from dual union all
  5     select 'user1', 21, date '2019-08-20' from dual union all
  6     select 'user1', 8,  date '2019-08-23' from dual union all
  7     --
  8     select 'user2', 3, date '2019-09-05'  from dual union all
  9     select 'user2', 9, date '2019-08-14'  from dual union all
 10     select 'user2', 8, date '2019-08-23'  from dual union all
 11     --
 12     select 'user3', 15, date '2019-08-06' from dual union all
 13     select 'user3', 1,  date '2019-08-30' from dual union all
 14     select 'user3', 7,  date '2019-09-14' from dual
 15    )
 16  select t.uname,
 17         max(case when (select max(1) from test t1
 18                        where t1.uname = t.uname
 19                          and t1.event = 21
 20                       ) = 1 then 21
 21                  else t.event
 22             end) event,
 23         max(t.tstamp) tstamp
 24  from test t
 25  group by t.uname
 26  order by t.uname;

UNAME      EVENT TSTAMP
----- ---------- ----------------
user1         21 2019-09-14 00:00
user2          9 2019-09-05 00:00
user3         15 2019-09-14 00:00

SQL>

Если есть event = 21, оно будет возвращено.Если нет, то будет возвращено событие MAX (что так же хорошо, как и любое другое значение, как вы сказали, что вас это не волнует) вместе с MAX tstamp для каждого uname.

2 голосов
/ 19 сентября 2019

Вот еще один способ, может быть, немного короче, чем другие:

select uname, 
       coalesce(max(case when event = 21 then event else null end), max(event)) event, 
       max(tstamp) 
          keep ( dense_rank first order by case when event = 21 THEN 0 ELSE 1 END asc,
                                           event desc ) tstamp 
from test
group by uname;    
2 голосов
/ 19 сентября 2019

CASE вернет 21, если есть 21, и NULL для всего остального.Тогда max вернет 21 или ноль

SQL DEMO

SELECT "uname"
      , MAX( CASE WHEN "event" = 21 THEN "event" END) as "event"
      , MAX( "tstamp" ) as "tstamp" 
FROM yourTable
GROUP BY "uname"
ORDER BY "uname";

ВЫХОД

| uname |  event |                tstamp |
|-------|--------|-----------------------|
| user1 |     21 | 2019-09-14 11:00:00.0 |
| user2 | (null) | 2019-09-05 11:00:00.0 |
| user3 | (null) | 2019-09-14 11:00:00.0 |
1 голос
/ 19 сентября 2019

Это еще одна короткая версия:

select uname,
  nvl(max(case event when 21 then 21 end), max(event)) event,
  nvl(max(case event when 21 then tstamp end), min(tstamp)) tstamp
from test
group by uname;

Демонстрация на Rextester .

...