PL/SQL에서 날짜 범위에 걸쳐 반복하는 방법
각 레코드의 날짜 범위가 있는 표에 대해 요약 합계를 생성하는 보고서를 작성해야 합니다.
table data:
option start_date end_date
opt1 6/12/2009 6/19/2009
opt1 6/3/2009 6/13/2009
opt2 6/5/2009 6/6/2009
제가 원하는 것은 기본적으로 다음과 같습니다.
date option count
6/1/2009 opt1 0
6/1/2009 opt2 0
6/2/2009 opt1 0
6/2/2009 opt2 0
6/3/2009 opt1 0
6/3/2009 opt2 1
날짜 범위에서 반복하는 방법을 찾는 데 어려움을 겪고 있습니다.저는 이것을 위해 만들 수 있는 간단한 커서라고 확신하지만 저는 당황스럽습니다.가급적이면 PL/SQL에서
업데이트:
저는 결국 제가 하고 싶은 일을 성취하기 위해 여기에 있는 예를 사용하게 되었습니다.이렇게 하면 날짜 표를 생성하는 함수가 생성됩니다.
이를 위해 제가 사용하는 한 가지 해결책은 날짜 범위를 for 루프에서 사용할 수 있는 정수 범위로 변환한 다음 다시 날짜 범위로 변환하여 작업을 수행하는 것입니다.이러한 방식으로는 조인이나 기타 작업을 수행할 수 없지만 이미 게시된 솔루션은 훨씬 작습니다.
declare
start_date number;
end_date number;
business_date varchar2(8);
begin
start_date := to_number(to_char(to_date('2013-04-25', 'yyyy-MM-dd'), 'j'));
end_date := to_number(to_char(to_date('2013-05-31', 'yyyy-MM-dd'), 'j'));
for cur_r in start_date..end_date loop
business_date := to_char(to_date(cur_r, 'j'), 'yyyy-MM-dd');
dbms_output.put_line(business_date);
end loop;
end;
일정 범위의 날짜를 반복하려면 일정한 일정이 필요합니다.저는 레벨 트릭에 의한 연결을 사용하여 하나를 만들었습니다.그런 다음 데이터와 일정관리를 결합할 수 있습니다(해당 날짜에 대한 옵션이 없는 경우에도 행을 원하므로 교차 결합).
SQL> WITH calendar AS (
2 SELECT to_date(:begin_date, 'mm/dd/yyyy') + ROWNUM - 1 c_date
3 FROM dual
4 CONNECT BY LEVEL <= to_date(:end_date, 'mm/dd/yyyy')
- to_date(:begin_date, 'mm/dd/yyyy') + 1
5 )
6 SELECT c_date "date", d_option "option", COUNT(one_day)
7 FROM (SELECT c.c_date, d.d_option,
8 CASE
9 WHEN c.c_date BETWEEN d.start_date AND d.end_date THEN
10 1
11 END one_day
12 FROM DATA d, calendar c)
13 GROUP BY c_date, d_option
14 ORDER BY 1,2;
date option COUNT(ONE_DAY)
----------- ------ --------------
01/06/2009 opt1 0
01/06/2009 opt2 0
02/06/2009 opt1 0
02/06/2009 opt2 0
03/06/2009 opt1 1
03/06/2009 opt2 0
04/06/2009 opt1 1
04/06/2009 opt2 0
05/06/2009 opt1 1
05/06/2009 opt2 1
06/06/2009 opt1 1
06/06/2009 opt2 1
12 rows selected
다른 기술과 마찬가지로 다음과 같은 방법으로 업데이트를 반복할 수 있습니다.
/* List of days for the past year, starting with today at midnight */
SELECT TRUNC(SYSDATE) + 1 - LEVEL AS today,
TRUNC(SYSDATE) + 2 - LEVEL AS tomorrow
FROM DUAL
CONNECT BY LEVEL <= 365
Using while loop (better)
declare
dfrom date;
dtill date;
day date;
begin
dfrom := TO_DATE('09.09.1988', 'dd.mm.yyyy');
dtill := TO_DATE('19.09.1988', 'dd.mm.yyyy');
day := dfrom;
WHILE day <= dtill
LOOP
DBMS_OUTPUT.PUT_LINE(day);
day := day + 1;
END LOOP;
end;
/
//using cursor
declare
dfrom date;
dtill date;
begin
dfrom := TO_DATE('09.09.1988', 'dd.mm.yyyy');
dtill := TO_DATE('19.09.1988', 'dd.mm.yyyy');
FOR cur IN (
SELECT dfrom + LEVEL - 1 AS today
FROM dual
CONNECT BY LEVEL <= dtill - dfrom + 1
) LOOP
DBMS_OUTPUT.PUT_LINE(cur.today);
END LOOP;
end;
/
위의 답변을 바탕으로 한 답변은 다음과 같습니다.시작 및 종료 날짜를 사용합니다.
2013년 7월 1일부터 2013년 7월 31일까지의 모든 날짜가 나열됩니다.모든 날짜 범위에 쉽게 적응할 수 있습니다.
SELECT to_date('07/01/2013', 'mm/dd/yyyy') + LEVEL - 1 AS today
FROM dual
CONNECT BY LEVEL <= to_date('07/31/2013', 'mm/dd/yyyy') - to_date('07/01/2013', 'mm/dd/yyyy') + 1;
이 유형의 쿼리는 범위를 특정 버킷으로 변환해야 하는 거의 모든 쿼리에 사용할 수 있는 두 번째 "유틸리티" 테이블이 있는 경우에 가장 잘 처리됩니다.유틸리티 테이블은 숫자 목록에 불과합니다.
CREATE TABLE Iterator (Counter NUMBER);
COUNTER
-------
0
1
2
3
...
100 (or however many rows you want to include)
예를 들어 30일을 표시할 것으로 가정합니다.
SELECT TO_DATE('6/1/2009', 'MM/DD/YYYY') + i.counter thedate
, i.My_option
, count(y.My_option)
FROM ( SELECT DISTINCT
i2.Counter
, y.My_option
FROM iterator i2
, YourTable y
WHERE i2.Counter < 5
) i
LEFT OUTER JOIN yourtable y
ON TO_DATE('6/1/2009', 'MM/DD/YYYY') + i.counter
>= y.start_date
AND TO_DATE('6/1/2009', 'MM/DD/YYYY') + i.counter
< y.end_date
AND y.My_option = i.My_option
GROUP BY TO_DATE('6/1/2009', 'MM/DD/YYYY') + i.counter
, i.My_option
ORDER BY 1
, 2;
즉, 반복기 테이블과 범위가 있는 테이블 사이에 데카르트 곱을 만든 다음 범위 조건이 충족되지 않는 모든 경우를 필터링합니다.이 방법은 여러 곳에서 사용할 수 있으며, 이 방법을 사용하면 항상 이산 구간으로 쉽게 변환할 수 있기 때문에 이산 구간이 아닌 범위를 사용하여 데이터를 모형화하는 것이 더 나은 가장 좋은 예 중 하나입니다.
편집: 날짜 범위 쿼리에 BETHIN을 정말 사용하면 안 됩니다 - >= <로 변경했습니다.
declare
v_curr_date date;
for i in to_number(to_char(p_date_from ,'j')) .. to_number(to_char(p_date_to
,'j')) loop
v_curr_date = to_date(to_char(i),'j');
--make any operation on v_curr_date (like insert into table)
end loop;
end;
언급URL : https://stackoverflow.com/questions/987610/how-to-iterate-over-a-date-range-in-pl-sql
'sourcecode' 카테고리의 다른 글
Angular2 재료 대화상자 자체 닫기 (0) | 2023.08.01 |
---|---|
이름을 가진 커서가 이미 존재하는 이유는 무엇입니까? (0) | 2023.08.01 |
">"(표시보다 큼) CSS 선택기는 무엇을 의미합니까? (0) | 2023.07.27 |
PHP에서 "비등한" 연산자 <>와 !=의 차이 (0) | 2023.07.27 |
Spring Boot과 함께 dotenv 파일 사용 (0) | 2023.07.27 |