Гость
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Группировка с нахождением новейших строк. / 25 сообщений из 36, страница 1 из 2
07.12.2020, 18:31
    #40025378
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Ура, впервые удалось спросить что-то по работе!

Посоветуйте, пожалуйста, как лучше построить запрос, который не только группирует строки, но также для каждой группы находит актуальную (самую недавнюю).

Пример: история цен для разных товаров. Товар определяется двумя колонками (продукт, цвет).
В некоторые дни цены обновляются, делая предыдущие неактуальными. Цены не более одного раза в день обновляются.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
with prices(day,price,prod,clr) as (
  select 1, 3.99, 'Apple', 'Green' from dual union all
  select 1, 2.49, 'Apple', 'Red'   from dual union all
  select 1, 5.99, 'Pear',  'Small' from dual union all
  select 2, 3.79, 'Apple', 'Green' from dual union all
  select 3, 3.69, 'Apple', 'Green' from dual
)
select prod,clr, ???? as LastUpdate, ???? as LastPrice from prices
 group by prod,clr



Нужно вывести прейскурант на сегодня, т.е. показать все товары, и сопутствующие элементы строки:
1, 2.49, 'Apple', 'Red'
1, 5.99, 'Pear', 'Small'
3, 3.69, 'Apple', 'Green'



Столько разных способов, не могу выбрать оптимальный. Кроме цены в строке полно столбцов, не хочется повторять аналитическую функцию для каждого.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
-- Простой и медленный: отфильтровать все старые цены
select * from prices p 
 where day=(select max(day) from prices t 
             where (p.prod,p.clr)=((t.prod,t.clr)))

-- через селф-джойн:
select p.* from prices p
  join (select max(day) LastDay, prod, clr from prices group by prod, clr) t 
      on (t.LastDay,t.prod,t.clr) = ((p.day,p.prod,p.clr))

-- через ранг, но теперь лишний столбец появился
select * 
  from (select p.*, dense_rank() over (partition by prod,clr order by day desc) rnk from prices p)
 where rnk = 1

-- аналитическими функциями, то тогда на каждый столбец - одинаковая долгая писанина
select distinct
  max(day)   keep (dense_rank last order by day) over (partition by prod,clr) as LastDay,
  max(price) keep (dense_rank last order by day) over (partition by prod,clr) as LastPrice,
  prod, clr 
  from prices

-- ну или так, но тоже писанина
select 
  max(day)   keep (dense_rank last order by day) as LastDay,
  max(price) keep (dense_rank last order by day) as LastPrice,
  prod, clr 
  from prices
 group by prod, clr



Второй вроде ничего, учитывая что селф-джойн идет по primary key (day,prod.clr),
но наверное кто-то знает еще лучше способ, ведь проблема сгруппировать, а потом выбрать лидера ис каждой группы наверное часто встречается.
...
Рейтинг: 0 / 0
07.12.2020, 18:47
    #40025380
Щукина Анна
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
...
Рейтинг: 0 / 0
07.12.2020, 18:52
    #40025384
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Щукина Анна,

кому баян, кому образование.

Спасибо за ссылку! Сижу, сравниваю со своими шедеврами.
...
Рейтинг: 0 / 0
07.12.2020, 18:56
    #40025386
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.


Баян может заиграть новыми мелодиями. Например match_recognize.

SY.
...
Рейтинг: 0 / 0
07.12.2020, 18:58
    #40025389
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Добавь поле ACTIVE и используй SCD2.

SY.
...
Рейтинг: 0 / 0
07.12.2020, 19:33
    #40025396
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Еще раз скажу - отличный баян!

Я там даже нашел понравившийся мне пример.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
select
  t2.*
from
  (  
    select
      id,
      min(rowid) "rowid" 
    from
      ttt 
    group by 
      id
  ) t1,
  ttt t2
where
  t1."rowid" = t2.rowid



отсюда: 1357243

Но... не работает. Нельзя rowid использовать ни с distinct, ни с group by.
...
Рейтинг: 0 / 0
07.12.2020, 20:03
    #40025407
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL

Я там даже нашел понравившийся мне пример.

Но... не работает. Нельзя rowid использовать ни с distinct, ни с group by.


Работать то он работает:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
select
  t2.*
from
  (
    select
      deptno,
      min(rowid) "rowid"
    from
      emp
    group by
      deptno
  ) t1,
  emp t2
where
  t1."rowid" = t2.rowid
/

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10

SQL>



Но искать смысловую нагрузку min(rowid) - типа самая ранняя строка это .

SY.
...
Рейтинг: 0 / 0
07.12.2020, 20:08
    #40025409
andreymx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
в 99% случаев делаю через row_number
Код: plsql
1.
2.
3.
4.
5.
select * from(
select grp, datetime, row_number() over(partition by grp order by datetime) rn
  from table
)
 where rn=1
...
Рейтинг: 0 / 0
07.12.2020, 20:17
    #40025412
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
SY,

лол, нет конечно не min(rowid). MAX (rowid)!

С инлайн вью конечно мне не стоило пытаться использовать rowid, d'oh!

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
create table prices(day integer, price number, prod varchar2(10), clr varchar2(10) );
insert into prices select * from (
  select 1, 3.99, 'Apple', 'Green' from dual union all
  select 1, 2.49, 'Apple', 'Red'   from dual union all
  select 1, 5.99, 'Pear',  'Small' from dual union all
  select 2, 3.79, 'Apple', 'Green' from dual union all
  select 3, 3.69, 'Apple', 'Green' from dual
);

select p.* 
  from (select max(rowid) keep (dense_rank last order by day) as therow from prices group by prod,clr) t
  join prices p on t.therow=p.rowid;



Собственно, то что я хотел с самого начала, но не получалось написать - забыл что у inline view не бывает rowid.
...
Рейтинг: 0 / 0
07.12.2020, 20:21
    #40025414
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
andreymx,

Тут просто коллекция решений растет. Вот бы кто-то FAQ написал на эту тему..

А есть способ потом крайнюю колонку как-нибудь спрятать или соскрести, не перечисляя все столбцы?
...
Рейтинг: 0 / 0
07.12.2020, 20:34
    #40025416
Щукина Анна
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL

А есть способ потом крайнюю колонку как-нибудь спрятать или соскрести, не перечисляя все столбцы?

Если версия сервера позволяет, то почему бы и нет?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
with 
  t (id, dt, txt) as 
    (
      select 1, date'2020-12-01', 'name1_1' from dual union all
      select 1, date'2020-12-02', 'name1_2' from dual union all
      select 1, date'2020-12-03', 'name1_3' from dual union all
      select 2, date'2020-12-01', 'name2_1' from dual union all
      select 2, date'2020-12-02', 'name2_2' from dual
    )
select *
  from t
  order by row_number() over(partition by id order by dt desc)
  fetch first 1 rows with ties;


Проверка на fiddle
...
Рейтинг: 0 / 0
07.12.2020, 20:35
    #40025417
SY
SY
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL

лол, нет конечно не min(rowid). MAX (rowid)!


Ты так ничего и не понял и как обычно в своем амплуа - кому нужны концепции. Ну нет корреляции между ROWID и временем вставки. MIN(ROWID) и MAX(ROWID) это ни первый ни последний.

SY.
...
Рейтинг: 0 / 0
07.12.2020, 21:28
    #40025423
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
SY,

Вообще-то я рассчитывал что клюнет env, но он видать спит.

Min/max в этом контексте работает одинаково, и от значений rowid не зависит, они в каждой группе одинаковые.
...
Рейтинг: 0 / 0
08.12.2020, 04:48
    #40025456
crutchmaster
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL
одинаковая долгая писанина

Это sql, смирись.
...
Рейтинг: 0 / 0
08.12.2020, 06:27
    #40025462
crutchmaster
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL,

Тебе его не победить. Он хорош, пока задача не вываливается далеко за рамки реляционной алгебры. Всё закончится тем, что ты свалишь писать генераторы sql-лапши на каком-нибудь яп общего назначения.
...
Рейтинг: 0 / 0
08.12.2020, 09:14
    #40025484
env
env
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL
Вообще-то я рассчитывал что клюнет env

Клюнет на что? На бред с min/max по rowid, который зависит от фазы Луны, положения Венеры в Тельце, enable row movement и прочих телодвижений с блоками?

НеофитSQL
они в каждой группе одинаковые

Концепции прочтите вы уже...
...
Рейтинг: 0 / 0
08.12.2020, 10:41
    #40025508
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
НеофитSQL

Но... не работает. Нельзя rowid использовать ни с distinct, ни с group by.


по одному наймолодшему в отделе

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  1  select * from emp where rowid in
  2* (select substr(max(to_char(hiredate,'yyyymmdd')||rowid),9) r from emp e2 group by deptno)
SQL> /

     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS      CLERK           7788 12.01.1983       1100                    20
      7900 JAMES      CLERK           7698 03.12.1981        950                    30
      7934 MILLER     CLERK           7782 23.01.1982       1300                    10

SQL>



.....
stax
...
Рейтинг: 0 / 0
08.12.2020, 11:00
    #40025515
andreymx
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Stax
НеофитSQL

Но... не работает. Нельзя rowid использовать ни с distinct, ни с group by.


по одному наймолодшему в отделе

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  1  select * from emp where rowid in
  2* (select substr(max(to_char(hiredate,'yyyymmdd')||rowid),9) r from emp e2 group by deptno)
SQL> /

     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS      CLERK           7788 12.01.1983       1100                    20
      7900 JAMES      CLERK           7698 03.12.1981        950                    30
      7934 MILLER     CLERK           7782 23.01.1982       1300                    10

SQL>




.....
stax
через опу можно сделать многое... но стОит ли?
...
Рейтинг: 0 / 0
08.12.2020, 11:07
    #40025523
Stax
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
andreymx
через опу можно сделать многое... но стОит ли?


в древних версиях стоило, счас наверное нет

я б делал через row_number

......
stax
...
Рейтинг: 0 / 0
08.12.2020, 14:41
    #40025600
K790
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
Stax
НеофитSQL

Но... не работает. Нельзя rowid использовать ни с distinct, ни с group by.


по одному наймолодшему в отделе

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
  1  select * from emp where rowid in
  2* (select substr(max(to_char(hiredate,'yyyymmdd')||rowid),9) r from emp e2 group by deptno)
SQL> /

     EMPNO ENAME      JOB              MGR HIREDATE          SAL       COMM     DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS      CLERK           7788 12.01.1983       1100                    20
      7900 JAMES      CLERK           7698 03.12.1981        950                    30
      7934 MILLER     CLERK           7782 23.01.1982       1300                    10

SQL>



.....
stax


Станислав, прочтите первое сообщение и предоставленные данные. Вы правильно оперируете с датами, но у автора
авторНужно вывести прейскурант на сегодня
Что в его понятии сегодня - непонятно
...
Рейтинг: 0 / 0
08.12.2020, 15:01
    #40025617
env
env
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
K790,

В запросах тем не менее у ТС есть поле day.
...
Рейтинг: 0 / 0
08.12.2020, 15:19
    #40025633
K790
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
env,

что это за day, тоже непонятно - ранк?
автор???? as LastUpdate, ???? as LastPrice
я опирался на этот момент - что этим хотел сказать автор?
...
Рейтинг: 0 / 0
08.12.2020, 15:25
    #40025635
K790
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
посыпаю голову пеплом, понял.
тогда вопрос как построена архитектура?
...
Рейтинг: 0 / 0
08.12.2020, 15:31
    #40025641
K790
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
извините, что слишком много, но тем не менее, приведенных планов нет и отвечать на вопрос
авторне могу выбрать оптимальный
не имеет смысла.
может там базенка на пару терабайт
...
Рейтинг: 0 / 0
08.12.2020, 17:58
    #40025712
НеофитSQL
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Группировка с нахождением новейших строк.
env
НеофитSQL
Вообще-то я рассчитывал что клюнет env

Клюнет на что? На бред с min/max по rowid, который зависит от фазы Луны, положения Венеры в Тельце, enable row movement и прочих телодвижений с блоками?

НеофитSQL
они в каждой группе одинаковые

Концепции прочтите вы уже...


Таки клюнул. Зачем? Уже ж все объяснили.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
with prices(day,price,prod,clr) as (
  select 1, 3.99, 'Apple', 'Green' from dual union all
  select 1, 2.49, 'Apple', 'Red'   from dual union all
  select 1, 5.99, 'Pear',  'Small' from dual union all
  select 2, 3.79, 'Apple', 'Green' from dual union all
  select 3, 3.69, 'Apple', 'Green' from dual
)
select prod,clr, MAX(price) keep (dense_rank last order by day) as therow from prices group by prod,clr



Вы разберетесь сами на этом примере, почему здесь МАХ не дает максимальную цену, и почему его можно заменить на MIN или AVG?
...
Рейтинг: 0 / 0
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Группировка с нахождением новейших строк. / 25 сообщений из 36, страница 1 из 2
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]