繁体   English   中英

使用Oracle SQL创建动态列

[英]Dynamic column creation with Oracle SQL

目前我正在研究固定资产注册报告棒,我需要在主查询中添加Projection列。

          Depreciation  Remaining Life of
Assed_No        Amount    asset in months
--------  ------------  -----------------
       1           400                  6
       2           200                  3
       3           100                  4
       4           600                  1

现在,我想在SQL中进行修改,根据月份列中资产的剩余寿命应该生成。 对于第一个资产,资产的剩余寿命为6个月,因此总共6个投影列的值应为400.如果剩余寿命小于最大值。 即6然后它应该为其余列提供0。

我想要如下的最终解决方案,

          Depreciation  Remaining Life of
Assed_No        Amount    asset in months  Projection 1  Projection 2  Projection 3  Projection 4  Projection 5  Projection 6
--------  ------------  -----------------  ------------  ------------  ------------  ------------  ------------  ------------
       1           400                  6           400           400           400           400           400           400
       2           200                  3           200           200             0             0             0             0
       3           100                  4           100           100           100           100             0             0
       4           600                  1           600             0             0             0             0             0

您可以为每个投影使用简单的大小写表达式:

-- CTE for sample data
with your_table (asset_no, amount, remaining_months) as (
            select 1, 400, 6 from dual
  union all select 2, 200, 3 from dual
  union all select 3, 100, 4 from dual
  union all select 4, 600, 1 from dual
)
-- query using my CTE column names
select asset_no, amount, remaining_months,
  case when remaining_months >= 1 then amount else 0 end as proj_1,
  case when remaining_months >= 2 then amount else 0 end as proj_2,
  case when remaining_months >= 3 then amount else 0 end as proj_3,
  case when remaining_months >= 4 then amount else 0 end as proj_4,
  case when remaining_months >= 5 then amount else 0 end as proj_5,
  case when remaining_months >= 6 then amount else 0 end as proj_6
from your_table;

  ASSET_NO     AMOUNT REMAINING_MONTHS     PROJ_1     PROJ_2     PROJ_3     PROJ_4     PROJ_5     PROJ_6
---------- ---------- ---------------- ---------- ---------- ---------- ---------- ---------- ----------
         1        400                6        400        400        400        400        400        400
         2        200                3        200        200        200          0          0          0
         3        100                4        100        100        100        100          0          0
         4        600                1        600          0          0          0          0          0

这基本上是Alex查询的动态版本(作为奖励!)

注意使用refcursor Bind变量。 当您在SQl * Plus中运行它或在SQL开发人员或Toad中作为脚本(F5)运行时,这将起作用。

您也可以在Oracle 12c及更高版本中使用DBMS_SQL.RETURN_RESULT来执行相同的操作。

VARIABLE x REFCURSOR;
DECLARE
v_case_expr VARCHAR2(1000);
BEGIN
SELECT
    listagg('CASE WHEN remaining_months > = '
              || level
              || ' 
                         then amount else 0 end as proj_'
              || level,',') WITHIN GROUP ( ORDER BY level)
INTO v_case_expr
FROM
    dual
CONNECT BY
    level <= (
        SELECT
            MAX(remaining_months)
        FROM
            assets
    );            

OPEN :x FOR 'select asset_no, amount, remaining_months, '
           || v_case_expr
           || ' FROM assets';END;
/

PRINT x;

PL/SQL procedure successfully completed.



  ASSET_NO     AMOUNT REMAINING_MONTHS     PROJ_1     PROJ_2     PROJ_3     PROJ_4     PROJ_5     PROJ_6
---------- ---------- ---------------- ---------- ---------- ---------- ---------- ---------- ----------
         1        400                6        400        400        400        400        400        400
         2        200                3        200        200        200          0          0          0
         3        100                4        100        100        100        100          0          0
         4        600                1        600          0          0          0          0          0

当计算量增加时,有时枢轴可能会更好。 这里我之前使用笛卡尔积来创建数据:

  with dat (asset_no, dep_amount, r_life)as 
  ( select 1, 400, 6 from dual union all 
    select 2, 200, 3 from dual union all
    select 3, 100, 4 from dual union all 
    select 4, 600, 1 from dual )
  , mon as (select level lv from dual connect by level <= 6)
  , bas as (
  select asset_no, dep_amount, r_life, lv, case when r_life >= lv then dep_amount else 0 end proj_m from dat, mon)
  select * 
  from bas
  pivot(sum(proj_m) for lv in (1 as proj_1,2 as proj_2,3 as proj_3,4 as proj_4,5 as proj_5,6 as proj_6)) 
  order by asset_no

认为带有案例表达的解决方案在这里更好

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM