Pl / SQL并从开始日期和停止日期构建月度数据

时间:2013-09-25 19:07:20

标签: oracle plsql

PL / SQL不是我强大的套件。我对SQL很不错,但是我有一个挑战,如果可能的话,我可以真正使用你的帮助。我正在使用SQL Developer,如果这有帮助的话。

我有一个表来自另外两个表的连接,但是它足以说明,它有以下应用程序列:

FTE_NAME              (VARCHAR2)
PRIMARY_BILLALBE_ROLE (VARCHAR2)
INVOICABLE_ALLOCATION (NUMBER)
CONTRACTED_FTE        (NUMBER)
FTE_COUNTRY           (VARCHAR2)
BILLING_START_DATE    (DATE)
BILLING_END_DATE      (DATE)

这是我想要做的一个例子:
 我实际上是使用VBA和excel完成的,它工作得很好,但现在数据在Oracle服务器上以及它的更新时间。

示例行:

|   FTE_NAME | PRIMARY_BILLABLE_ROLE | INVOICEABLE_ALLOCATION | CONTRACTED_FTE | FTE_COUNTRY | BILLING_START_DATE | BILLING_END_DATE |
|------------|-----------------------|------------------------|----------------|-------------|--------------------|------------------|
| John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |     May, 01 2013 |
| John Smith |               Manager |                      1 |              1 |         USA |       May, 02 2013 |           (null) |

我需要做的是PL / SQL代码会构建一个月度表,并逐行包含或排除该月中的行,因此从01-JAN-201305-MAY-2013,每月表格现在看起来像这样,前面有一个MONTH COLUMN:

|           MONTHLY |   FTE_NAME | PRIMARY_BILLABLE_ROLE | INVOICEABLE_ALLOCATION | CONTRACTED_FTE | FTE_COUNTRY | BILLING_START_DATE | BILLING_END_DATE |
|-------------------|------------|-----------------------|------------------------|----------------|-------------|--------------------|------------------|
|  January, 01 2013 | John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |    May, 01 2013  |
| February, 01 2013 | John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |    May, 01 2013  |
|    March, 01 2013 | John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |    May, 01 2013  |
|    April, 01 2013 | John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |    May, 01 2013  |
|      May, 01 2013 | John Smith |     Associate Manager |                      1 |              1 |         USA |   January, 01 2013 |    May, 01 2013  |
|      May, 01 2013 | John Smith |               Manager |                      1 |              1 |         USA |       May, 02 2013 |           (null) |

MAY的行都会包含在01-MAY-2013行中,因为该经理在这几天仍然担任助理经理。我使用开始和结束日期来计算天数。

我需要帮助的重要部分是如何使用MONTHLY列使用该月的第一天来构建表。每天有1000多条线路和每栋建筑物。我会在视图中运行此代码,该视图将提供报告和仪表板。

我非常感谢您提供的任何帮助。

大卫

1 个答案:

答案 0 :(得分:0)

您可以像在此示例查询中一样从头开始填充所需的日期:

with report_params as (
  -- just to introduce variables 
  select 
    2013 year_value,
    4    start_month,
    6    end_month
  from  dual
),
report_months as (
  -- list of first dates of all required months 
  select 
    add_months( -- add months to
        trunc( -- January, 1st of year from parameters
          to_date(
            (select year_value from report_params), 
            'yyyy'
          ),
          'yyyy'
        ), 
        (select start_month from report_params) + level - 2
    )
  from 
    dual 
  connect by 
    -- select number of rows (levels) from start_month to end_month
    level <= (select end_month - start_month + 1 from report_params)
)
select * from report_months;

另一种可能性是分析表并在最小值和最大值之间生成diapason:

with bound_months as (
  select 
    min(trunc(billing_start_date,'mm')) as first_month,
    max(trunc(billing_start_date,'mm')) as last_month
  from 
    applicable_columns
),
report_months as (
  select 
    add_months(
      (select first_month from bound_months),
      level - 1
    )
      as first_date
  from 
    dual 
  connect by 
    -- select number of rows (levels) from start_month to end_month
    level <= (select months_between(last_month,first_month)+1 from bound_months)

)
select * from report_months;

之后,您可以使用适用的列将月份列表连接到数据表/视图:

with bound_months as (
  select 
    min(trunc(billing_start_date,'mm')) as first_month,
    max(trunc(billing_start_date,'mm')) as last_month
  from 
    applicable_columns
),
report_months as (
  select 
    add_months(
      (select first_month from bound_months),
      level - 1
    )
      as first_date
  from 
    dual 
  connect by 
    -- select number of rows (levels) from start_month to end_month
    level <= (select months_between(last_month,first_month)+1 from bound_months)

)
select
  months.first_date, 
  data.*
from 
 report_months      months,
 applicable_columns data
where 
 data.billing_start_date < add_months(months.first_date,1) 
 and
 nvl(data.billing_end_date, months.first_date) >= months.first_date
order by
  first_date, fte_name, primary_billable_role

<强> SQLFiddle test