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

max по rowid для блока with построенного на dual? Месье знает толк в извращениях.
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025715
Фотография env
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На этом примере куда лучше видно, что адекватно формулировать свою задачу у вас не получается.
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025719
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
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


Вы, однако, извращенец.

После моего комментария я увидел что загвоздка с rowid была из-за inline views, я вначале неправильно прочитал сообщение об ошибке, и написал об этом. 22243959

А потом кто-то увидел max(rowid), недочитал строку, и началось...
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025723
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
K790
посыпаю голову пеплом, понял.
тогда вопрос как построена архитектура?


Пример был игрушечный, т.к. ответ на него отвечал на мой вопрос - как получить "главную" строку из каждой группы без дополнительных колонок. Главную - как определяет мой критерий сортировки, и группировка по нескольким колонкам.
В игрушечном примере группировка по двум колонкам, а сортировка - по "day".

Я подозревал что ответ который дает колонку rowid - оптимальный, потому что доступ по rowid бесплатный, и потому что rowid существует, исходя из постановки задачи (выдать строки целиком по критерию). Но у меня не получалось его написать, т.к. я забыл что у CTE нет rowid.

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


Некоторым танцорам штаны мешают ;-)
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025727
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
НеофитSQL

Вы разберетесь сами на этом примере, почему здесь МАХ не дает максимальную цену, и почему его можно заменить на MIN или AVG?


авторЦены не более одного раза в день обновляются

обновите цену два раза в день (без времени), и будет Вам max

ps
если order by ... не уникально строку с помощью keep не выбрать

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

Потом, с подсказкой от SY и других, все получилось. 22243959


??? Моя "подсказка" была с MAX/MIN ROWID ничего не выйдет. Stax показал "дедовский" метод которым мы пользовались в дремучие времена когда Oracle не поддерживал аналитические ф-ции. А моя основная "подсказка" была используй SCD2 - цена меняется мах 2 раза в день а выбирается куда больше раз. Так-что потери на изменение цены через SCD2 с лихвой окупятся при выборке.

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

Тогда условия задачи требуют корректировки, т.к. "последняя цена" не определена. Если "любая из последних", то MAX подойдет, и MIN подойдет, а вот с AVG будут проблемы.

Эх, надо было AVG(rowid) написать. Жаль, что это не число :)

Для параноиков как я, в таблицу можно добавить уникальный constraint по (prod,clr,day).
A в квери - поставить "бомбу" которая ее сломает если все-таки появились дупликаты.
Чтоб неповадно.
...
Рейтинг: 0 / 0
Группировка с нахождением новейших строк.
    #40025750
НеофитSQL
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
SY
НеофитSQL

Потом, с подсказкой от SY и других, все получилось. 22243959


??? Моя "подсказка" была с MAX/MIN ROWID ничего не выйдет. Stax показал "дедовский" метод которым мы пользовались в дремучие времена когда Oracle не поддерживал аналитические ф-ции. А моя основная "подсказка" была используй SCD2 - цена меняется мах 2 раза в день а выбирается куда больше раз. Так-что потери на изменение цены через SCD2 с лихвой окупятся при выборке.

SY.


Я говорил про 22243953 .
Там пример был чужой и сломанный, но теперь у меня свой и как env уже увидел, правильно работающий.

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

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

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


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