#sql #oracle #oracle-sqldeveloper
#sql #Oracle #oracle-sqldeveloper
Вопрос:
У меня есть таблица, которая выглядит следующим образом:
ID Product DATE
1 A 1
1 B 1
1 A 2
1 B 2
1 A 3
1 B 3
2 A 1
2 B 1
2 A 2
2 B 2
2 A 3
2 B 3
. .
. .
Я хочу, чтобы для каждого идентификатора и каждого продукта отображались строки только для первой и последней даты. Таким образом, результат будет выглядеть следующим образом:
ID Product DATE
1 A 1
1 B 1
1 A 3
1 B 3
2 A 1
2 B 1
2 A 3
2 B 3
При этом мне удалось получить только первую дату:
select *
from (
select t.*, rank() over(partition by t.ID order by t.DATE) rn
from t
) t
where rn = 1
Это правильный путь? И как я могу также добавить последнюю дату?
Комментарии:
1. Вы получили 4 ответа и приняли единственный неправильный!
Ответ №1:
Я бы использовал оконные функции:
select t.*
from (select t.*,
min(date) over (partition by id) as min_date,
max(date) over (partition by id) as max_date
from t
) t
where date in (min_date, max_date);
Альтернативный метод заключается в использовании коррелированных подзапросов:
select t.*
from t
where t.date = (select min(t.date)
from t t2
where t2.id = t.id
) or
t.date = (select max(t.date)
from t t2
where t2.id = t.id
) ;
Комментарии:
1. Спасибо, я не был знаком с функциями окна, таким образом, он работал намного лучше и быстрее, чем я себе представлял.
Ответ №2:
Что-то вроде этого? Используйте MIN
и MAX
агрегируйте функции. Строки # 1 — 13 представляют образцы данных (вы их не вводите); необходимый запрос начинается со строки # 14.
SQL> with test (id, product, datum) as
2 (select 1, 'A', 1 from dual union all
3 select 1, 'B', 1 from dual union all
4 select 1, 'A', 2 from dual union all
5 select 1, 'B', 2 from dual union all
6 select 1, 'A', 3 from dual union all
7 select 1, 'B', 3 from dual union all
8 --
9 select 2, 'A', 1 from dual union all
10 select 2, 'B', 1 from dual union all
11 select 2, 'A', 2 from dual union all
12 select 2, 'B', 2 from dual
13 )
14 select id, product,
15 min(datum) datum
16 from test
17 group by id, product
18 --
19 union
20 --
21 select id, product,
22 max(datum) datum
23 from test
24 group by id, product
25 order by id, datum, product;
ID PRODUCT DATUM
---------- ---------- ----------
1 A 1
1 B 1
1 A 3
1 B 3
2 A 1
2 B 1
2 A 2
2 B 2
8 rows selected.
SQL>
Комментарии:
1. Спасибо, это работает для этой таблицы, но если в таблице больше столбцов, которые я хочу включить в выходные данные, это усложняется, и функции окна, предложенные в другом ответе, кажутся проще и быстрее.
Ответ №3:
Вы можете сделать это с RANK()
помощью (или ROW_NUMBER()
, если нет повторяющихся дат) оконной функции:
SELECT t.ID, t.Product, t."DATE"
FROM (
SELECT t.*,
RANK() OVER (PARTITION BY t.ID, t.Product ORDER BY t."DATE") rn_min,
RANK() OVER (PARTITION BY t.ID, t.Product ORDER BY t."DATE" DESC) rn_max
FROM tablename t
) t
WHERE 1 IN (rn_min, rn_max)
ORDER BY t.ID, t."DATE", t.Product
Смотрите демонстрацию.
Результаты:
> ID | PRODUCT | DATE
> -: | :------ | ---:
> 1 | A | 1
> 1 | B | 1
> 1 | A | 3
> 1 | B | 3
> 2 | A | 1
> 2 | B | 1
> 2 | A | 3
> 2 | B | 3
Ответ №4:
Еще одним вариантом является использование first_value
last_value
аналитической функции and следующим образом:
Select id, product, date from
(Select t.*,
First_value(date) over (partition by id, product order by date) as fdate,
Last_value(date) over (partition by id, product order by date) as ldate
From your_table t)
Where date = fdate or date = ldate;