oracle - по группам - без агрегации - PullRequest
0 голосов
/ 03 апреля 2020

У меня есть таблица oracle, где ref_id - это поле флага - это тип данных, а ORN - порядок данных в каждом ref_id:

ref_id   data    ORN   flag
  1       100     0     0
  1       200     1     0
  1       300     2     0
  1       400     3     0
  1       110     0     1
  1       210     1     1
  1       150     0     2
  1       250     1     2
  1       350     2     2
  1       450     3     2
  2       500     0     0
  2       600     1     0
  2       700     2     0
  2       800     3     0
  2       120     0     1
  2       220     1     1
  2       320     1     1
  2       420     1     1
  2       170     0     2
  2       270     1     2
  2       370     2     2
  2       470     3     2

Мне нужно сгруппировать данные в способ получить последние данные в флаге 0 и последние данные в флаге 2 для каждого ref_id

, поэтому новая таблица будет выглядеть примерно так:

ref_id    data_1    data_2
  1        400       450
  2        800       470

любой намек, как это сделать sh это без использования петель?

Ответы [ 3 ]

1 голос
/ 03 апреля 2020

Вы можете использовать аналитическую функцию и группу следующим образом:

SELECT REF_ID, 
       MAX(CASE WHEN FLAG = 0 THEN DATA END) AS DATA_0,
       MAX(CASE WHEN FLAG = 2 THEN DATA END) AS DATA_2
FROM
(
  SELECT REF_ID, DATA, ORN, FLAG,
         ROW_NUMBER() OVER (PARTITION BY REF_ID, FLAG ORDER BY ORN DESC) AS RN
  FROM YOUR_TABLE 
  WHERE FLAG IN (0,2)
)
WHERE RN = 1
GROUP BY REF_ID
0 голосов
/ 03 апреля 2020

Вы можете использовать агрегатные функции (ПЕРВЫЙ / ПОСЛЕДНИЙ) для этой цели.

https://docs.oracle.com/database/121/SQLRF/functions074.htm#SQLRF00641

https://docs.oracle.com/database/121/SQLRF/functions095.htm#SQLRF00653.

with t (ref_id,data,ORN,flag) as (
select   1,       100,     0,     0 from dual union all
select   1,       200,     1,     0 from dual union all
select   1,       300,     2,     0 from dual union all
select   1,       400,     3,     0 from dual union all
select   1,       110,     0,     1 from dual union all
select   1,       210,     1,     1 from dual union all
select   1,       150,     0,     2 from dual union all
select   1,       250,     1,     2 from dual union all
select   1,       350,     2,     2 from dual union all
select   1,       450,     3,     2 from dual union all

select   2,       500,     0,     0 from dual union all
select   2,       600,     1,     0 from dual union all
select   2,       700,     2,     0 from dual union all
select   2,       800,     3,     0 from dual union all
select   2,       120,     0,     1 from dual union all
select   2,       220,     1,     1 from dual union all
select   2,       320,     1,     1 from dual union all
select   2,       420,     1,     1 from dual union all
select   2,       170,     0,     2 from dual union all
select   2,       270,     1,     2 from dual union all
select   2,       370,     2,     2 from dual union all
select   2,       470,     3,     2 from dual 
)
select 
  ref_id
, max(decode(flag, 0, data)) keep (dense_rank last order by decode(flag, 0, 100, 50), orn ) x
, max(decode(flag, 2, data)) keep (dense_rank last order by decode(flag, 2, 100, 50), orn ) y 
-- or
, min(decode(flag, 0, data)) keep (dense_rank first order by decode(flag, 0, 50, 100), orn desc) xx
, min(decode(flag, 2, data)) keep (dense_rank first order by decode(flag, 2, 50, 100), orn desc) yy

from t
group by ref_id

    REF_ID          X          Y         XX         YY
---------- ---------- ---------- ---------- ----------
         1        400        450        400        450
         2        800        470        800        470
0 голосов
/ 03 апреля 2020

В качестве альтернативы используйте двухэтапный подход , сначала (в CTE) выберите только значения столбца DATA, который соответствует последнему ORN в пределах REF_ID

Обратите внимание, что в случае, если ORN не является уникальным, вы можете получить более одной строки с разными значениями.

На следующем шаге простое агрегирование на REF_ID, I Я использую функцию max, то есть получим самое высокое значение DATA в случае связей.

В случае уникального сочетания REF_ID и ORN (первичный ключ) вы можете использовать MIN и MAX взаимозаменяемо, но полезно знать, что они обеспечат diffremt result , если допустимы дублирования.

with agg as (
select 
 REF_ID,FLAG, DATA, ORN,
 case when flag = 0  and ORN = max(ORN) over (partition by REF_ID, FLAG) then data end as data_0,
 case when flag = 2  and ORN = max(ORN) over (partition by REF_ID, FLAG) then data end as data_2
from tab
)
select  REF_ID, 
 max(data_0) as data_0,
 max(data_2) as data_2
from agg
group by REF_ID
order by 1;

Здесь результат CTE

    REF_ID       FLAG       DATA        ORN     DATA_0     DATA_2
---------- ---------- ---------- ---------- ---------- ----------
         1          0        100          0                      
         1          0        200          1                      
         1          0        300          2                      
         1          0        400          3        400           
         1          1        110          0                      
         1          1        210          1                      
         1          2        150          0                      
         1          2        250          1                      
         1          2        350          2                      
         1          2        450          3                   450
...

и результат окончательного запроса

    REF_ID     DATA_0     DATA_2
---------- ---------- ----------
         1        400        450
         2        800        470   
...