Oracle - 执行递归 'WITH' 查询时检测到循环
Oracle - Cycle detected while executing recursive 'WITH' query
我正在使用 oracle sql 做一个递归查询的基本示例。我正在计算格式 MON-YY 的未来月份。我设法得到了一个看似正确的查询,但我不明白 WITH 查询的中断条件。
我试图打破年份值(例如,当你到达 2020 年时停止),但它在这样做时检测到一个周期。如果我打破月份值(例如 12 月),它会起作用。
这是我基于一个月的休息时间的查询:
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;
如果我这样做,它 returns 一个一致的结果。
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
现在,如果我尝试打破年份的递归查询,假设是 2020 年,那么我将 with 子句中的 where 条件更改为:
where annee < 20
然后我得到:
ORA-32044: cycle detected while executing recursive WITH query
我试了一个月后断了,看看我的年份加法是否正确,似乎是这样。如果我在 3 月中断,我会正确地得到 1 月和 2 月:
where mois <> 'mar'
给予
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
jan 20
fev 20
mar 20
您的主要问题是您试图使用 strings/numbers 来操纵日期。不要那样做;如果您使用日期,请使用日期!
例如你可以像这样做你想做的事:
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
N.B。您可以将递归子分解查询中的谓词简化为 mnth_dt < add_months(TRUNC(SYSDATE, 'yyyy'), 11)
.
这是通过获取开始日期(在这里,我使用了 sysdate
)并找到该月的第一天(通过使用可选的第二个参数 TRUNC
来指定我们的级别)来实现的正在将其截断为)。
然后我们只需在每个日期上加一个月,直到到达开始日期所在年份的最后一个月。
只有在您获得日期后,您才能使用 to_char
.
以您需要的格式输出数据
使用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
db<>fiddle here
我正在使用 oracle sql 做一个递归查询的基本示例。我正在计算格式 MON-YY 的未来月份。我设法得到了一个看似正确的查询,但我不明白 WITH 查询的中断条件。
我试图打破年份值(例如,当你到达 2020 年时停止),但它在这样做时检测到一个周期。如果我打破月份值(例如 12 月),它会起作用。
这是我基于一个月的休息时间的查询:
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;
如果我这样做,它 returns 一个一致的结果。
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
现在,如果我尝试打破年份的递归查询,假设是 2020 年,那么我将 with 子句中的 where 条件更改为:
where annee < 20
然后我得到:
ORA-32044: cycle detected while executing recursive WITH query
我试了一个月后断了,看看我的年份加法是否正确,似乎是这样。如果我在 3 月中断,我会正确地得到 1 月和 2 月:
where mois <> 'mar'
给予
MOI ANNEE
--- ----------
sep 19
oct 19
nov 19
dec 19
jan 20
fev 20
mar 20
您的主要问题是您试图使用 strings/numbers 来操纵日期。不要那样做;如果您使用日期,请使用日期!
例如你可以像这样做你想做的事:
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
N.B。您可以将递归子分解查询中的谓词简化为 mnth_dt < add_months(TRUNC(SYSDATE, 'yyyy'), 11)
.
这是通过获取开始日期(在这里,我使用了 sysdate
)并找到该月的第一天(通过使用可选的第二个参数 TRUNC
来指定我们的级别)来实现的正在将其截断为)。
然后我们只需在每个日期上加一个月,直到到达开始日期所在年份的最后一个月。
只有在您获得日期后,您才能使用 to_char
.
使用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
db<>fiddle here