powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Группировка с нахождением новейших строк.
25 сообщений из 36, страница 1 из 2
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025380
Фотография Щукина Анна
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025384
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Щукина Анна,

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

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


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

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

SY.
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025407
Фотография 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
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025414
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andreymx,

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

А есть способ потом крайнюю колонку как-нибудь спрятать или соскрести, не перечисляя все столбцы?
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025417
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
НеофитSQL

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


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

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

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

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

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

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

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

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

Концепции прочтите вы уже...
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025523
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreymx
через опу можно сделать многое... но стОит ли?


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

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

......
stax
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #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
Группировка с нахождением новейших строк.
    #40025617
Фотография env
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
K790,

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

что это за day, тоже непонятно - ранк?
автор???? as LastUpdate, ???? as LastPrice
я опирался на этот момент - что этим хотел сказать автор?
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025635
K790
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
посыпаю голову пеплом, понял.
тогда вопрос как построена архитектура?
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025641
K790
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
извините, что слишком много, но тем не менее, приведенных планов нет и отвечать на вопрос
авторне могу выбрать оптимальный
не имеет смысла.
может там базенка на пару терабайт
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #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
25 сообщений из 36, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Группировка с нахождением новейших строк.
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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