是否可以在Oracle上创建一个计算列?

时间:2017-01-03 18:43:22

标签: sql oracle

我有一张表格,显示我项目每一步的统计数据。它看起来像这样:

ITEM    STEP_1    STEP_2    STEP_3    STEP_4    STEP_5
-----  --------  --------  --------  --------  --------
1        OK        NOK        OK        NOK    IN ANALYSIS
2        OK        OK         OK        OK     N/A
3        NOK       NOK        NOK       NOK    NOK

我想要做的是使用新的进度列创建一个视图。像这样:

ITEM    STEP_1    STEP_2    STEP_3    STEP_4    STEP_5       Progress
-----  --------  --------  --------  --------  --------     -----------
1        OK        NOK        OK        NOK    ANALYSIS        40%
2        OK        OK         OK        OK     N/A             100%
3        NOK       NOK        NOK       NOK    NOK              0%

百分比值是通过将每个步骤中的“OK”或“N / A”相加并除以步骤总数(在本例中为5)得到的。

可以这样做吗?

编辑1。:

喜欢这个吗?

ITEM    STEPs     STATUS 
-----  --------  --------
1       Step_1     OK
1       Step_2     NOK
1       Step_3     NOK
1       Step_4     ANALYSIS
1       Step_5     OK      

Edit.2:

以下是我正在进行规范化的简化版本:

SELECT

T.*

FROM
    ( SELECT DISTINCT
    ITEM_ID,

      (SELECT FINAL_STATUS
      FROM book_new b
      WHERE a.ITEM_ID        = b.ITEM_ID
      AND b.STEPS        = 'STEP_1'
      ) AS STEP_1 ,

      (SELECT FINAL_STATUS
      FROM book_new b
      WHERE a.ITEM_ID        = b.ITEM_ID
      AND b.STEPS        = 'STEP_2'
      ) AS STEP_2 ,

      (SELECT FINAL_STATUS
      FROM book_new b
      WHERE a.ITEM_ID        = b.ITEM_ID
      AND b.STEPS        = 'STEP_3'
      AND ROWNUM = 1
      ) AS STEP_3 ,

      (SELECT FINAL_STATUS
      FROM book_new b
      WHERE a.ITEM_ID        = b.ITEM_ID
      AND b.STEPS        = 'STEP_4'
      AND ROWNUM = 1
      ) AS STEP_4 ,

      (SELECT FINAL_STATUS
      FROM book_new b
      WHERE a.ITEM_ID        = b.ITEM_ID
      AND b.STEPS        = 'STEP_5'
      AND ROWNUM = 1
      ) AS STEP_5

FROM book_new A

    ) T

2 个答案:

答案 0 :(得分:1)

只需定义您要使用的计算并包含别名:

name

如果您希望计算根据belongs_to列的数量动态更改,那么您运气不佳。 RDBMS通常不是为处理动态列而设计的。

此外,正如duffymo指出的那样,在正确标准化的设计中,这将更加容易。这也可以让你动态调整步数。

答案 1 :(得分:1)

如果您从非规范化数据开始,您可以使用分析计数查询找到每个项目的“正常”步骤百分比:

select item_id, steps, final_status,
  100 * count(case when final_status in ('OK', 'N/A') then final_status end)
    over (partition by item_id) -- analytic function with windowing clause
  / count(steps) over (partition by item_id) as percent_ok
from book_new
order by item_id, steps;

   ITEM_ID STEPS  FINAL_ST PERCENT_OK
---------- ------ -------- ----------
         1 STEP_1 OK               40
         1 STEP_2 NOK              40
         1 STEP_3 NOK              40
         1 STEP_4 ANALYSIS         40
         1 STEP_5 OK               40
         2 STEP_1 OK               100

...

然后,您可以将其转换为所需的表格格式;在11gR2或更高版本上,您可以使用内置数据透视运算符:

select item_id, a_step as step_1, b_step as step_2, c_step as step_3,
  d_step as step_4, e_step as step_5, percent_ok || '%' as progress
from (
  select item_id, steps, final_status,
    100 * count(case when final_status in ('OK', 'N/A') then final_status end)
      over (partition by item_id)
    / count(steps) over (partition by item_id) as percent_ok
  from book_new
)
pivot (max(final_status) as step for (steps) in ('STEP_1' as a, 'STEP_2' as b,
  'STEP_3' as c, 'STEP_4' as d, 'STEP_5' as e))
order by item_id;

   ITEM_ID STEP_1   STEP_2   STEP_3   STEP_4   STEP_5   PROGRESS                  
---------- -------- -------- -------- -------- -------- --------------------------
         1 OK       NOK      NOK      ANALYSIS OK       40%                       
         2 OK       OK       OK       OK       N/A      100%                       
         3 NOK      NOK      NOK      NOK      NOK      0%                        

在早期版本中,您可以使用聚合函数在案例表达式上手动转动数据:

select item_id,
  max(case when steps = 'STEP_1' then final_status end) as step_1,
  max(case when steps = 'STEP_2' then final_status end) as step_2,
  max(case when steps = 'STEP_3' then final_status end) as step_3,
  max(case when steps = 'STEP_4' then final_status end) as step_4,
  max(case when steps = 'STEP_5' then final_status end) as step_5,
  percent_ok || '%' as progress
from (
  select item_id, steps, final_status,
    100 * count(case when final_status in ('OK', 'N/A') then final_status end)
      over (partition by item_id)
    / count(steps) over (partition by item_id) as percent_ok
  from book_new
)
group by item_id, percent_ok
order by item_id;

得到相同的结果(无论如何11g都是这样做的。)

您使用子查询的方法效率不会非常高,因为您多次查询同一个表。但是,通过这种方法,您仍然可以使用@ Allan的答案 - 只需更改外部SELECT T.* FROM以列出列并以相同方式进行计算。

您可以在文档中详细了解analytic functionspivoting

顺便说一句,您也可以稍微改变计算进度的方式。如果一个步骤是N / A那么根据它计算可能没有意义;您可以改为将内部查询更改为忽略这些,仅用于计算:

  select item_id, steps, final_status,
    100 * count(case when final_status = 'OK' then final_status end)
      over (partition by item_id)
    / count(case when final_status != 'N/A' then final_status end)
      over (partition by item_id) as percent_ok
  from book_new

这对您的样本数据没有任何影响,但如果您有一个N / A项目,而其他项目除了OK之外,那么百分比就会上升。这可能不是你想要的,但它是一个选择......