Oracle 在给定的示例中,最接近参考日期的是同一天(2012年1月1日),年份日期=1。如果我的问题不够清楚,很抱歉。也许我不明白,但您要查找的日期是存储在表中还是只查找最近的日期?问得好。我认为捕获的是闰年。如果您查找2000年前后的366,最近的可能是4年。@B
Oracle 在给定的示例中,最接近参考日期的是同一天(2012年1月1日),年份日期=1。如果我的问题不够清楚,很抱歉。也许我不明白,但您要查找的日期是存储在表中还是只查找最近的日期?问得好。我认为捕获的是闰年。如果您查找2000年前后的366,最近的可能是4年。@B,oracle,date,Oracle,Date,在给定的示例中,最接近参考日期的是同一天(2012年1月1日),年份日期=1。如果我的问题不够清楚,很抱歉。也许我不明白,但您要查找的日期是存储在表中还是只查找最近的日期?问得好。我认为捕获的是闰年。如果您查找2000年前后的366,最近的可能是4年。@Ben,不幸的是,日期是存储在表中的注释。它包含修改的日期、开始日期、结束日期(例如:2012年12月31日、365、1,在这种情况下,预期转换为365=2012年12月30日和2013年1月1日。修改的日期接近日期值,但可以在日期值之前、之间或
在给定的示例中,最接近参考日期的是同一天(2012年1月1日),年份日期=1。如果我的问题不够清楚,很抱歉。也许我不明白,但您要查找的日期是存储在表中还是只查找最近的日期?问得好。我认为捕获的是闰年。如果您查找2000年前后的366,最近的可能是4年。@Ben,不幸的是,日期是存储在表中的注释。它包含修改的日期、开始日期、结束日期(例如:2012年12月31日、365、1,在这种情况下,预期转换为365=2012年12月30日和2013年1月1日。修改的日期接近日期值,但可以在日期值之前、之间或之后(例如:2012年12月31日、1、1)。现在,我面临一个将这些日期转换为实际日期值的问题。虽然日期之间的间隔保证小于365,因此不需要复杂的解决方案,但我认为我将使函数足够简单,可以处理任何一般情况。为什么
sysdate=“01/01/2012”input=1 result=“01/01/2012”
而不是result=“01/02/2012”
?@rene,我认为有一些混淆。要求是,对于参考日期(比如sysdate),找到与年中日期最接近的日期(sql中的“DDD”)。因此,任何日期都可以作为参考,并且一个介于1和366之间的值作为年中的日期。对于给定的示例,它本身就是同一天(2012年1月1日)最接近参考日期,日期=1。如果我的问题不够清楚,很抱歉。谢谢彼得森。这有点暴力(但不是你的错)。这无疑为结合我的逻辑简化执行提供了可能性。谢谢彼得森。这有点暴力(但这不是你的错)。这无疑为结合我的逻辑简化执行提供了一种可能性。
sysdate = "01/01/2012" input = 365 result = "31/12/2011"
sysdate = "01/01/2012" input = 366 result = "31/12/2012"
sysdate = "01/01/2012" input = 1 result = "01/01/2012"
sysdate = "31/12/2012" input = 1 result = "01/01/2013"
CREATE OR REPLACE PROCEDURE test(ref_date_str varchar2, doy number) IS
ref_date date ;
nearest_date date ;
BEGIN
ref_date := to_date(ref_date_str, 'dd/mm/yyyy') ;
WITH choices AS
(
SELECT trunc(ref_date, 'yyyy') + doy - 1 AS choice_date FROM dual
UNION
SELECT trunc(trunc(ref_date, 'yyyy') - 1, 'yyyy') + doy - 1 AS choice_date FROM dual
UNION
SELECT add_months(trunc(ref_date, 'yyyy'), 12) + doy - 1 AS choice_date FROM dual
)
SELECT choice_date INTO nearest_date FROM choices WHERE abs(ref_date - choice_date) =
(SELECT min(abs(ref_date - choice_date)) FROM choices) AND rownum < 2 ;
dbms_output.put_line(to_char(nearest_date, 'dd/mm/yyyy')) ;
END ;
/
for each year backwards from current year
if a valid date found for the doy, and it is <= sysdate
first_date = this valid date
exit loop
for each year forward from current year
if a valid date found for the doy, and it is > sysdate
second_date = this valid date
exit loop
chosen_date = closest_to_sysdate_among(first_date, second_date)
CREATE OR REPLACE FUNCTION GetNearestDate(reference_date DATE, day_of_year NUMBER) RETURN DATE IS
valid_date_1 DATE ;
valid_date_2 DATE ;
iter_date DATE ;
BEGIN
iter_date := trunc(reference_date, 'yyyy') ;
WHILE TRUE
LOOP
valid_date_1 := iter_date + day_of_year - 1 ;
IF valid_date_1 < add_months(iter_date, 12) AND valid_date_1 <= reference_date THEN
EXIT ;
END IF ;
iter_date := trunc(iter_date - 1, 'yyyy') ;
END LOOP ;
iter_date := trunc(reference_date, 'yyyy') ;
WHILE TRUE
LOOP
valid_date_2 := iter_date + day_of_year - 1 ;
IF valid_date_2 < add_months(iter_date, 12) AND valid_date_2 > reference_date THEN
EXIT ;
END IF ;
iter_date := add_months(iter_date, 12) ;
END LOOP ;
IF abs(valid_date_1 - reference_date) <= abs(valid_date_2 - reference_date) THEN
RETURN valid_date_1 ;
END IF ;
RETURN valid_date_2 ;
END ;
/
with dates as
(SELECT to_date('01-01-1980', 'DD-MM-YYYY') + rownum day,
to_number(to_char(to_date('01-01-1980', 'DD-MM-YYYY') + rownum,
'DDD')) day_of_year
FROM ALL_OBJECTS
WHERE ROWNUM <= 100 * 365)
select t.*
from (select dates.*,
abs(to_date('01-01-2012', 'DD-MM-YYYY') - dates.day) diff
from dates
where dates.day_of_year = 1
order by 3) t
where rownum <= 1
CREATE OR REPLACE FUNCTION GetNearestDate(reference_date DATE, day_of_year NUMBER) RETURN DATE IS
nearest_date DATE ;
BEGIN
SELECT valid_date INTO nearest_date
FROM
(
SELECT first_date + day_of_year - 1 AS valid_date
FROM
(
SELECT add_months(trunc(reference_date, 'YYYY'), (rownum-10) * 12) AS first_date
FROM all_objects
WHERE rownum <= 20
)
WHERE to_char(first_date, 'YYYY') = to_char(first_date + day_of_year - 1, 'YYYY')
ORDER BY abs(first_date + day_of_year - 1 - reference_date), first_date
)
WHERE rownum < 2 ;
RETURN nearest_date ;
EXCEPTION WHEN OTHERS THEN
RETURN nvl(reference_date, sysdate) ;
END ;
/