在PL / SQL中填充两个日期范围之间的日期维度

时间:2015-11-08 03:27:05

标签: sql plsql oracle11g

我是plsql的新手,并且在我的任务中遇到了一些麻烦。我被要求创建一个日期维度表并用各种日期信息填充它。

我按如下方式创建了我的表

CREATE TABLE date_dimension_table
(  
v_date DATE NOT NULL,
full_date VARCHAR2(50) NOT NULL,
day_of_week NUMBER(1,0) NOT NULL,
day_in_month NUMBER(2,0) NOT NULL,
day_in_year NUMBER(3,0) NOT NULL,
last_day_of_week_flag VARCHAR2(1) NOT NULL,
last_day_of_month_flag VARCHAR2(1) NOT NULL,
end_of_week_date DATE NOT NULL,
month_number NUMBER(2,0) NOT NULL,
month_name VARCHAR2(32) NOT NULL,
year_month CHAR(32) NOT NULL,
quarter_number NUMBER(1,0) NOT NULL,
year_and_quarter VARCHAR2(32) NOT NULL,
v_year NUMBER(4,0) NOT NULL,
CONSTRAINT date_dimension_table_PK PRIMARY KEY (v_date)
);

然后我创建了以下过程来填充表格。

create or replace PROCEDURE sp_populate_dates(
v_first_date_in DATE,
v_second_date_in DATE)

AS
--Declare two variables as DATE datatypes
v_current_date DATE;
v_end_date     DATE;

BEGIN

--Assign the start date and end date to the variables
v_current_date := TO_DATE(v_first_date_in, 'DDMMYYYY');
v_end_date := TO_DATE(v_second_date_in, 'DDMMYYYY');


--Delete whats currently in the table
DELETE FROM date_dimension_table;

--condition checks if the first date is before the second date
WHILE v_current_date <= v_end_date
LOOP
--insert into table
INSERT INTO date_dimension_table
(
    v_date,
    full_date,
    day_of_week,
    day_in_month,
    day_in_year,
    last_day_of_week_flag,
    last_day_of_month_flag,
    end_of_week_date,
    month_number,
    month_name,
    year_month,
    quarter_number,
    year_and_quarter,
    v_year       
)    
VALUES
(
    v_current_date,                                 --date
    TO_CHAR(v_current_date, 'Day, Month DD, YYYY'), --full date
    TO_NUMBER(TO_CHAR(v_current_date, 'D')) -1,     --day in week
    TO_CHAR(v_current_date,'DD'),                   --day in month        
    TO_CHAR(v_current_date,'DDD'),                  --day in year
    CASE                                            --last day of week flag
        WHEN TO_CHAR(v_current_date,'FMDay') = 'Sunday' THEN 'Y'
        ELSE 'N'
    END,
    CASE                                            --last day of month flag
        WHEN last_day(TO_DATE(v_current_date, 'MM/DD/YYYY')) = TO_DATE(v_current_date, 'MM/DD/YYYY') THEN 'Y'
        ELSE 'N'
    END,
    CASE                                            --date of next sunday
        WHEN TO_CHAR(v_current_date,'FMDay') = 'Sunday' THEN v_current_date
        ELSE NEXT_DAY(v_current_date,'SUNDAY')
    END,
    TO_CHAR(v_current_date,'MM'),                   --month number
    TO_CHAR(v_current_date,'MONTH'),                --name of month
    TO_CHAR(v_current_date,'MONTH YYYY'),           --month and year        
    TO_CHAR(v_current_date,'Q'),                    --number of quarter
    TO_CHAR(v_current_date,'YYYY Q'),               --year and quarter
    TO_CHAR(v_current_date,'YYYY')                  --year    

);
--Increment and assign the current date value to be re-evaluated
v_current_date := v_current_date + 1;

END LOOP;
END;

由于程序必须插入一系列日期的信息,我使用了两个日期作为输入参数,并且它引发了一个错误。

示例:

BEGIN
sp_populate_dates(01/01/2005, 01/01/2006);
END;

然后我得到错误,表明调用函数是错误的参数类型。我想知道是否有人可以帮忙解决这个问题,并告诉我哪里出错了。干杯

3 个答案:

答案 0 :(得分:1)

首先,你有程序获得

v_first_date_in DATE,
v_second_date_in DATE

DATE ,但您尝试传递的不是字符串。试试这样的事情

BEGIN
sp_populate_dates(TO_DATE('01/01/2005', 'dd/mm/yyyy'), TO_DATE('01/01/2005', 'dd/mm/yyyy'));
END;

另一件事是 - 您在过程中处理这些参数,因此您可能想要传递varchar2类型变量。这意味着,

create or replace PROCEDURE sp_populate_dates(
v_first_date_in IN VARCHAR2,
v_second_date_in IN VARCHAR2)
...

并将其称为

BEGIN
sp_populate_dates('01/01/2005','01/01/2005');
END;

但请注意:如果此处的日期类型为(&#39; dd / mm / yyyy&#39;),则您在此过程中的处理日期(&#39; ddmmyyyy&#39;)不正确。< / p>

希望它会有所帮助!

答案 1 :(得分:0)

如果您真的不需要任何日期格式化和解析,请始终使用SQL标准DATE literal

BEGIN
  sp_populate_dates(DATE '2005-01-01', DATE '2006-01-01');
END;

答案 2 :(得分:0)

您可以使用以下查询填充此类表格(针对2000年至2030年之间的日期):

CREATE TABLE DIM_DATE
as
(
 select
  TO_NUMBER(TO_CHAR(DATE_D,'j')) as DATE_J,
  DATE_D,
  TO_CHAR(DATE_D,'YYYY-MM-DD') as DATE_V,
  TO_NUMBER(TO_CHAR(DATE_D,'YYYY')) as YEAR_NUM,
  TO_NUMBER(TO_CHAR(DATE_D,'Q')) as QUARTER_NUM,
  TO_NUMBER(TO_CHAR(DATE_D,'MM')) as MONTH_NUM,
  TRIM(TO_CHAR(DATE_D,'Month','nls_date_language=english')) as MONTH_DESC,
  TO_NUMBER(TO_CHAR(DATE_D,'IW')) as ISO_WEEK_NUM,
  TO_NUMBER(TO_CHAR(DATE_D,'IYYY')) as ISO_YEAR_NUM,
  TO_NUMBER(TO_CHAR(DATE_D,'DD')) as DAY_OF_MONTH_NUM,
  TO_NUMBER(TO_CHAR(DATE_D,'D')) as DAY_OF_WEEK_NUM,
  TRIM(TO_CHAR(DATE_D,'Day','nls_date_language=english')) as DAY_OF_WEEK_DESC,
  (CASE WHEN TRIM(TO_CHAR(DATE_D,'Day','nls_date_language=english')) IN ('Saturday','Sunday') THEN 'Weekend' ELSE 'Weekday' END) as DAY_TYPE_DESC
 from
 (
 select
  to_date('1999-12-31','YYYY-MM-DD')+ROWNUM as DATE_D
 from
  dual
  connect by level <= to_date('2029-12-31','YYYY-MM-DD')-to_date('1999-12-31','YYYY-MM-DD') 
 )
);