일년 중 특정 날짜의 가장 가까운 날짜 (sysdate를 기준으로)를 찾는 간단한 솔루션을 찾고 있습니다.Oracle sql 쿼리 가장 가까운 날짜의 연도
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"
(형식 "일/월/년"에서) 예를 들면 기본적으로 결과 날짜는 현재 연도, 전년도 또는 내년에있을 수 있습니다. 처음에 저는 아래 주어진 작은 절차를 작성했습니다. 여기에 sysdate 대신 참조 날짜를 사용하여 결과를 테스트합니다. 이것은 일년 중 입력 된 날짜가 366이 아닌 경우에 효과적입니다. 그러나 366 일 때 이것은 실패하고 가장 가까운 유효한 날짜를 찾기 위해 더 멀리 앞으로 이동해야 할 수도 있습니다. 윤년 (모든 조건 4,100,400 등)에 대한 검사를 추가 한 후 코드는 진짜 난장판이되었습니다.
더 간단하고, 더 좋고, 절대 안전한 솔루션 (기능 또는 단일 쿼리)을 제안 할 수 있다면 감사하겠습니다. 오라클에 너무 복잡한 복잡한 구조를 사용하지 마십시오. 동일한 구조로 DB2를 포팅해야합니다. 또한 효율성은 심각하게 실행되지 않으므로 최소한의 관심사입니다. 아래 내가 위에서 준 알고리즘의 구현 (일부가 :
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 ;
/
논리적으로 내가 고려하고있는 알고리즘은 & 안부, Reji
EDIT 1이
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 ;
/
편집 2 : 체크? "valid_date_ < ADD_MONTHS"는이 날짜가 같은 (반복) 년 자체 (그렇지 않으면 비 윤년 366의 값이 다음 반환에 있는지 확인하는 것입니다 년 시작일). 또한 참조 날짜와의 관련 비교는 (reference = "30/01/2012", input = 365) 같은 경우를 방지하는 것입니다. 여기에서 첫 번째 값은 연중 날짜 값이 365 인 가장 가까운 날짜이므로 유효 날짜 값은 '31/12/2011 '이 아니고'30/12/2012 '가 아니어야합니다.
아마도 내가 이해하지 못 하겠지만 찾고있는 날짜가 테이블에 저장되어 있거나 가장 가까운 날짜를 찾고 있습니까? – Ben
좋은 질문입니다. 나는 그 잡기가 도약이라고 생각한다. 2000 년경에 366 명을 찾으면 가장 가까운 사람은 4 년 뒤입니다. – Rene
@Ben, 불행히도 날짜는 메모가 테이블에 저장됩니다. 수정 된 날짜, 시작일, 종료일을 포함합니다 (예 : 31/12/2012, 365, 1). 예상 전환은 365 = 30/12/12 및 1 = 01/01/2013입니다.modified_date는 요일 값에 가깝지만, 그 이전, 중간 또는 이후 일 수 있습니다 (예 : 31/12/2012, 1, 1). 이제 저는 요즘을 실제 날짜 값으로 변환하는 문제에 직면 해 있습니다. 요일 사이의 격차가 365 이하로 보장되지만 복잡한 솔루션이 필요하지는 않지만 일반적인 상황을 처리 할 수있을 정도로 기능을 충분히 보장 할 것이라고 생각했습니다. – mpathi