Oracle - обнаружен цикл при выполнении рекурсивного запроса WITH - PullRequest
1 голос
/ 20 сентября 2019

Я делаю простой пример рекурсивного запроса с оракулом sql.Я вычисляю будущие месяцы в формате MON-YY.Мне удалось получить, казалось бы, правильный запрос, но я не понимаю условие разрыва с запросом WITH.

Я пытаюсь разбить значение года (например, остановка при достижении 2020 года), но этообнаруживает цикл при этом.Если я разбиваю значение месяца (например, декабрь), оно работает.

Вот мой запрос с перерывом на месяц:

with
    prochains_mois(mois, annee) as (
        select 'sep' as mois, 19 as annee
        from dual
    union all
        select 
            case mois
                when 'jan' then 'fev'
                when 'fev' then 'mar'
                when 'mar' then 'avr'
                when 'avr' then 'mai'
                when 'mai' then 'jun'
                when 'jun' then 'jui'
                when 'jui' then 'aou'
                when 'aou' then 'sep'
                when 'sep' then 'oct'
                when 'oct' then 'nov'
                when 'nov' then 'dec'
                when 'dec' then 'jan'
            end,
            case mois
                when 'dec' then annee + 1
                else annee
            end
        from prochains_mois r
        where mois <> 'dec'
    )
select * from prochains_mois;

Если я это сделаю, он вернёт согласованный результат.

MOI      ANNEE
--- ----------
sep         19
oct         19
nov         19
dec         19

Теперь, если я попытаюсь разбить рекурсивный запрос на год, скажем, 2020, поэтому я изменю условие where в предложении with на:

where annee < 20

Тогда я получу:

ORA-32044: cycle detected while executing recursive WITH query

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

where mois <> 'mar'

дает

MOI      ANNEE
--- ----------
sep         19
oct         19
nov         19
dec         19
jan         20
fev         20
mar         20

Ответы [ 2 ]

1 голос
/ 20 сентября 2019

Используйте DATE s:

with prochains_mois( value ) as (
  select DATE '2019-09-01' from dual
union all
  select ADD_MONTHS( value, 1 )
  FROM   prochains_mois
  WHERE  value < DATE '2020-12-01'
)
select SUBSTR( TO_CHAR( value, 'mon', 'NLS_DATE_LANGUAGE=FRENCH' ), 1, 3 ) AS mois,
       TO_CHAR( value, 'RR' ) AS annee
from   prochains_mois;

Вывод :

MOIS | ANNEE
:--- | :----
sep  | 19   
oct  | 19   
nov  | 19   
dec  | 19   
jan  | 20   
fev  | 20   
mar  | 20   
avr  | 20   
mai  | 20   
jui  | 20   
jui  | 20   
aou  | 20   
sep  | 20   
oct  | 20   
nov  | 20   
dec  | 20   

или используйте свой запрос и проверьте, что месяц и год не совпадают:

with
    prochains_mois(mois, annee) as (
        select 'sep' as mois, 19 as annee
        from dual
    union all
        select 
            case mois
                when 'jan' then 'fev'
                when 'fev' then 'mar'
                when 'mar' then 'avr'
                when 'avr' then 'mai'
                when 'mai' then 'jun'
                when 'jun' then 'jui'
                when 'jui' then 'aou'
                when 'aou' then 'sep'
                when 'sep' then 'oct'
                when 'oct' then 'nov'
                when 'nov' then 'dec'
                when 'dec' then 'jan'
            end,
            case mois
                when 'dec' then annee + 1
                else annee
            end
        from prochains_mois r
        where ( mois, annee ) NOT IN ( ( 'dec', 20 ) )
    )
select * from prochains_mois;

Вывод :

MOIS | ANNEE
:--- | ----:
sep  |    19
oct  |    19
nov  |    19
dec  |    19
jan  |    20
fev  |    20
mar  |    20
avr  |    20
mai  |    20
jun  |    20
jui  |    20
aou  |    20
sep  |    20
oct  |    20
nov  |    20
dec  |    20

дБ <>скрипка здесь

0 голосов
/ 20 сентября 2019

Ваша главная проблема в том, что вы пытаетесь манипулировать датами, используя строки / числа.Не делай этого;если вы работаете с датами, используйте даты!

Например, вы можете делать то, что вам нужно, вот так:

WITH prochains_mois (mnth_dt) AS (SELECT TRUNC(sysdate, 'mm') mnth_dt
                                  FROM   dual
                                  UNION ALL
                                  SELECT add_months(mnth_dt, 1) mnth_dt
                                  FROM   prochains_mois
                                  WHERE add_months(mnth_dt, 1) < add_months(TRUNC(sysdate, 'yyyy'), 12))
SELECT mnth_dt,
       to_char(mnth_dt, 'mon') mois,
       to_char(mnth_dt, 'yy') annee
FROM   prochains_mois;

MNTH_DT     MOIS ANNEE
----------- ---- -----
01/09/2019  sep  19
01/10/2019  oct  19
01/11/2019  nov  19
01/12/2019  dec  19

NB Вы можете упростить предикат в рекурсивном субфакторингезапрос к mnth_dt < add_months(TRUNC(SYSDATE, 'yyyy'), 11).

Это работает, беря дату начала (здесь я использовал sysdate) и находя первое число месяца (используя необязательный второй параметр TRUNC, чтобы указатьдо уровня, к которому мы его усекаем).

Затем мы просто добавляем месяц к каждой дате, пока не достигнем последнего месяца года начальной даты.

Только после того, как вы получилидаты вы затем выводите данные в нужном вам формате, используя to_char.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...