powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Даты и цены - запрос Oracle
6 сообщений из 6, страница 1 из 1
Даты и цены - запрос Oracle
    #40040744
StuDentBakalavr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Задана таблица Цена_товара с данными о датах и ценах на товар. Нужно было написать запрос для определения интервалов спада и нарастания цен. Например, для таблицы


результат должен быть таков


Я написал следующий запрос:

Код: 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.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
ALTER SESSION SET NLS_DATE_LANGUAGE = 'AMERICAN';
/* НАЧАЛЬНАЯ ТАБЛИЦА С ДАТАМИ И ЦЕНАМИ */
WITH TEST AS (  SELECT TO_DATE('01.09.2012', 'DD.MM.SYYYY') "ДАТА", 35 "ЦЕНА"
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('02.09.2012', 'DD.MM.SYYYY'), 34
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('03.09.2012', 'DD.MM.SYYYY'), 33
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('04.09.2012', 'DD.MM.SYYYY'), 34
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('05.09.2012', 'DD.MM.SYYYY'), 35
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('06.09.2012', 'DD.MM.SYYYY'), 36
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('07.09.2012', 'DD.MM.SYYYY'), 37
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('08.09.2012', 'DD.MM.SYYYY'), 36
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('09.09.2012', 'DD.MM.SYYYY'), 35
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('10.09.2012', 'DD.MM.SYYYY'), 34
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('11.09.2012', 'DD.MM.SYYYY'), 35
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('12.09.2012', 'DD.MM.SYYYY'), 36
                FROM DUAL
                UNION ALL
                SELECT TO_DATE('13.09.2012', 'DD.MM.SYYYY'), 38
                FROM DUAL
                                
                ORDER BY 1),
 
/* ТАБЛИЦА, СОДЕРЖАЩАЯ КОНТРОЛЬНЫЕ ДАТЫ */
POINT_DATES AS (SELECT DISTINCT T2."ДАТА" AS POINT
                FROM TEST T1, TEST T2, TEST T3
                WHERE 
                    T1."ДАТА" < T3."ДАТА"
                      AND
                      (
                        /* ВКЛЮЧАЕМ В ТАБЛИЦУ НАЧАЛЬНУЮ ДАТУ */
                        T2."ДАТА" = (SELECT "ДАТА" FROM TEST WHERE ROWNUM = 1)
                        /* ВКЛЮЧАЕМ КОНЕЧНУЮ ДАТУ */
                        OR T2."ДАТА" = (SELECT MAX("ДАТА") FROM TEST)
                        /* ДОБАВЛЯЕМ ЛОКАЛЬНЫЕ МИНИМУМЫ И МАКСИМУМЫ */
                        OR (SELECT COUNT("ДАТА") FROM TEST WHERE "ДАТА" < T3."ДАТА" AND "ДАТА" > T1."ДАТА") = 1
                        AND (T2."ДАТА" < T3."ДАТА" AND T2."ДАТА" > T1."ДАТА")
                        AND (
                            T2."ЦЕНА" > T1."ЦЕНА" AND T2."ЦЕНА" > T3."ЦЕНА"
                            OR T2."ЦЕНА" < T1."ЦЕНА" AND T2."ЦЕНА" < T3."ЦЕНА"
                        )
                      )
                ORDER BY 1 ASC),
                
/* ТАБЛИЦА С ИНТЕРВАЛАМИ СПАДА ЦЕНЫ НА ТОВАР */
COST_DOWN AS (SELECT DISTINCT T1.POINT START_DOWN, T2.POINT END_DOWN
                FROM POINT_DATES T1, POINT_DATES T2
                WHERE 
                  T2.POINT > T1.POINT
                  AND (SELECT "ЦЕНА" FROM TEST WHERE "ДАТА" = T2.POINT) < (SELECT "ЦЕНА" FROM TEST WHERE "ДАТА" = T1.POINT)
                  /* ЕСЛИ НЕСКОЛЬКО ПРОМЕЖУТКОВ СПАДА ЦЕНЫ, ТО ВКЛЮЧАЕМ САМЫЕ МЕНЬШИЕ */
                  AND T2.POINT = (
                    SELECT POINT 
                    FROM POINT_DATES 
                    WHERE 
                      POINT > T1.POINT 
                      AND (POINT - T1.POINT) = (
                        SELECT MIN(POINT - T1.POINT) 
                        FROM POINT_DATES 
                        WHERE POINT > T1.POINT)
                  )
            /* ДОБАВЛЯЕМ NULL ЗНАЧЕНИЯ ДЛЯ СЛУЧАЯ, КОГДА СНАЧАЛА ИДЕТ РОСТ ЦЕНЫ */
            UNION ALL SELECT NULL START_DOWN, NULL END_DOWN FROM DUAL
            ),
 
/* ТАБЛИЦА С ИНТЕРВАЛАМИ РОСТА ЦЕНЫ */
COST_UP AS (SELECT DISTINCT T1.POINT START_UP, T2.POINT END_UP
            FROM POINT_DATES T1, POINT_DATES T2
            WHERE 
              T2.POINT > T1.POINT
              AND (SELECT "ЦЕНА" FROM TEST WHERE "ДАТА" = T2.POINT) > (SELECT "ЦЕНА" FROM TEST WHERE "ДАТА" = T1.POINT)
              /* АНАЛОГИЧНО, ЕСЛИ НЕСКОЛЬКО ИНТЕРВАЛОВ РОСТА ЦЕНЫ, БЕРЕМ МЕНЬШИЕ */
              AND T2.POINT = (
                SELECT POINT 
                FROM POINT_DATES 
                WHERE 
                  POINT > T1.POINT 
                  AND (POINT - T1.POINT) IN (
                    SELECT MIN(POINT - T1.POINT) 
                    FROM POINT_DATES 
                    WHERE POINT > T1.POINT))
        /* ДОБАВЛЯЕМ NULL ЗНАЧЕНИЯ ДЛЯ СЛУЧАЯ, КОГДА В КОНЦЕ ИДЕТ СПАД ЦЕНЫ */
        UNION ALL SELECT NULL START_UP, NULL END_UP FROM DUAL
        )
 
/*  ОСНОВНОЙ ЗАПРОС */
SELECT  NVL(TO_CHAR(START_DOWN, 'DD-MON-YY'), ' ') "НАЧАЛО СПАДА", 
        NVL(TO_CHAR(END_DOWN, 'DD-MON-YY'), ' ') "ОКОНЧАНИЕ СПАДА", 
        NVL(TO_CHAR(START_UP, 'DD-MON-YY'), ' ') "НАЧАЛО РОСТА", 
        NVL(TO_CHAR(END_UP , 'DD-MON-YY'), ' ') "ОКОНЧАНИЕ РОСТА"
FROM COST_DOWN, COST_UP
WHERE
    /* СОЕДИНЯЕМ ТАБЛИЦЫ ПО РАВЕНСТВУ ДАТ КОНЦА СПАДА И НАЧАЛА РОСТА */
    END_DOWN = START_UP
    OR
    /* УЧИТЫВАЕМ СЛУЧАЙ, КОГДА В НАЧАЛЕ ИДЕТ РОСТ ЦЕНЫ */
    START_UP IS NOT NULL AND END_UP IS NOT NULL AND START_DOWN IS NULL AND END_DOWN IS NULL 
    AND (SELECT COUNT(*) FROM COST_DOWN WHERE COST_DOWN.END_DOWN = START_UP) = 0
    OR
    /*  УЧИТЫВАЕМ СЛУЧАЙ, КОГДА В КОНЦЕ ИДЕТ СПАД ЦЕНЫ */
    START_DOWN IS NOT NULL AND END_DOWN IS NOT NULL AND START_UP IS NULL AND END_UP IS NULL 
    AND (SELECT COUNT(*) FROM COST_UP WHERE COST_UP.START_UP = END_DOWN) = 0
/* СОРТИРУЕМ ПО ВОЗРАСТАНИЮ ДАТЫ НАЧАЛА СПАДА ЦЕНЫ */
ORDER BY START_DOWN ASC NULLS FIRST;



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

Как возможно это исправить?
...
Рейтинг: 0 / 0
Даты и цены - запрос Oracle
    #40040746
Фотография SeaGate
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
StuDentBakalavr,

SQL for Pattern Matching
...
Рейтинг: 0 / 0
Даты и цены - запрос Oracle
    #40040780
Фотография Stax
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
StuDentBakalavr,

какая версия оракля?

и что делать со стабильностью (полочкой)?

ps
match_recognize -там пример какраз спада-наростания (W)

.....
stax
...
Рейтинг: 0 / 0
Даты и цены - запрос Oracle
    #40042756
StuDentBakalavr
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stax,

SqlDeveloper 17.4.0.355; это задача из ВУЗа
...
Рейтинг: 0 / 0
Даты и цены - запрос Oracle
    #40042778
Фотография Vadim Lejnin
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
StuDentBakalavr,

Мессир, Вы проходили тему Клиент-Сервер?

Код: plsql
1.
select * from v$version;
...
Рейтинг: 0 / 0
Даты и цены - запрос Oracle
    #40045756
newuser0311
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как-то так (с учетом ровных интервалов):
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
with t as (
select dt1, dt2, sign(tt2.n-tt1.n) sg from 
(select d dt1, lead(d) over(order by d) dt2 from
    (select d, n, x from
        (select d, n, sg,  sg+lag(sg) over(order by d) x  from
            (select d, n, sign(pr - n) sg from
                (select d, n, lead(n) over(order by d) pr   from test)))
    where (x between -1 and 1 and sg <> 0) or (x is null) or (x<>0 and sg=0))), 
    test tt1, test tt2
where tt1.d = dt1 and tt2.d = dt2 
order by dt1),
t1 as (select row_number() over(order by dt1) rn,
dt1, dt2 from t where sg =-1),
t2 as (select row_number() over(order by dt1) rn,
dt1, dt2 from t where sg =1)
select t1.dt1 "Начало спада", t1.dt2 "Окончание спада", 
t2.dt1 "Начало роста", t2.dt2 "Окончание роста" from t1 full join t2
on t1.rn = t2.rn
order by t1.dt1
...
Рейтинг: 0 / 0
6 сообщений из 6, страница 1 из 1
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Даты и цены - запрос Oracle
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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