【问题标题】:Oracle SQL Calculated Column - How do I reference a calculated column in another calculation in the same query?Oracle SQL 计算列 - 如何在同一查询的另一个计算中引用计算列?
【发布时间】:2019-11-23 02:18:47
【问题描述】:

我想在同一查询中的另一个计算中使用计算列。但据我所知,Oracle SQL 似乎不允许我这样做。这些似乎是一个简单的数据操作,我可以在 Python 中轻松完成,但 Oracle SQL 似乎具有挑战性。

例如:

表格

日期 |值1 |价值2

所需的查询功能

SELECT
date,
value1,
value2,
(value2 * value1) AS value_calculated
(value_calculated * 100) AS value_calculated_2
(value_calculated_2 * 1000) AS value_calculated_3

FROM  table

如果这是不可能的,我认为 Oracle 应该将其内置到他们的软件中。

在其他 Stack Overflow 问题/响应中,CROSS APPLY 出现了。这对我不起作用,因为我需要创建 10-20 个计算列(所有这些列都引用其他计算列)。

我可以创建一个简单的 PL/SQL 函数来将它们指定为用于其他列计算的对象吗?

问题更新:

这是我正在做的事情的完整代码,使用 Oracle Cloud Financials 19C

WITH segment_desc AS(
SELECT DISTINCT
flex_value,
description
FROM
fnd_flex_values_vl
WHERE description NOT IN('Default')

),
balances_calc AS(
SELECT
gl_balances.period_name,
gl_ledgers.ledger_id,
gl_ledgers.name,
gl_ledgers.currency_code||'-'||gl_balances.currency_code 
func_ent_curr_pair,
gl_code_combinations.code_combination_id,
gl_code_combinations.segment1,
gl_code_combinations.segment2,
segment_desc.description center_description,
gl_code_combinations.segment3,
gl_code_combinations.segment4,
gl_code_combinations.segment5,

gl_balances.currency_code ent_curr_cd,
-- balance logic swap functional/entered if ent=func
CASE
    WHEN gl_balances.currency_code = gl_ledgers.currency_code
        THEN NVL(gl_balances.begin_balance_dr_beq,0) - 
NVL(gl_balances.begin_balance_cr_beq,0) -- return functional "beq"
                ELSE NVL(gl_balances.begin_balance_dr,0) - 
NVL(gl_balances.begin_balance_cr,0) -- return entered "balances_cr/dr"
                    END
ent_beg_balance,

-- activity logic swap functional/entered if func=ent
CASE
    WHEN gl_balances.currency_code = gl_ledgers.currency_code
    THEN NVL(gl_balances.period_net_dr_beq,0) - 
NVL(gl_balances.period_net_cr_beq,0)   -- return functional "beq"
                ELSE NVL(gl_balances.period_net_dr,0) - 
NVL(gl_balances.period_net_cr,0) -- return entered "balances_cr/dr"
                    END
ent_activity,

gl_ledgers.currency_code func_curr_cd,

NVL(gl_balances.begin_balance_dr_beq,0) - 
NVL(gl_balances.begin_balance_cr_beq,0) func_beg_balance,
NVL(gl_balances.period_net_dr_beq,0) - 
NVL(gl_balances.period_net_cr_beq,0) func_activity,

-- if statement currency equals
CASE
    WHEN gl_balances.currency_code = gl_ledgers.currency_code
        THEN 'TRUE'
                ELSE 'FALSE'
                    END
entered_equals_functional,
gl_balances.translated_flag

FROM
gl_balances, gl_code_combinations, gl_ledgers, segment_desc
WHERE
1 = 1
AND gl_code_combinations.chart_of_accounts_id = '2001'
AND (gl_balances.translated_flag IN ('N','R') OR 
gl_balances.translated_flag IS NULL)
AND gl_balances.code_combination_id = 
gl_code_combinations.code_combination_id
AND gl_ledgers.ledger_id = gl_balances.ledger_id
AND  segment_desc.flex_value (+) = gl_code_combinations.segment2

),


balances_calc_test AS(
SELECT 
balances_calc.period_name,
balances_calc.segment1,
balances_calc.segment2,
balances_calc.segment3,
balances_calc.segment4,
**calc_column.func_end_balance,**
**calc_column_2.custom_calc**

FROM balances_calc

**CROSS APPLY(SELECT func_beg_balance + func_activity AS func_end_balance 
FROM balances_calc) calc_column**
**CROSS APPLY(SELECT func_end_balance - ent_activity AS custom_calc FROM 
balances_calc) calc_column_2**
)

SELECT * FROM balances_calc_test

这会在查询中返回错误

我在 calc_column.func_end_balance 列中得到重复值。

我应该使用 WHERE 语句来加入吗?

再次,我认为需要有一个更简单的解决方案来进行派生列计算。 Python Pandas 可以在 2 秒内完成。

【问题讨论】:

  • 您需要使用子查询、CTE 或横向连接。
  • 感谢您的帮助,非常感谢。
  • @JesseNicholson 我怀疑是否有任何 SQL 实现允许这样做。 SQL 语言一般不喜欢被告知以什么顺序做事。

标签: python sql oracle pandas plsql


【解决方案1】:

这是标准的 SQL 功能,它的定义是有充分理由的:数据库不需要以任何顺序评估 select 表达式。因此,没有“之前”别名可供查看。

正常的解决方案是 CTE 或子查询:

SELECT t.*,
       (value_calculated_2 * 1000) AS value_calculated_3
FROM (SELECT t.*,
             (value_calculated * 100) AS value_calculated_2 
      FROM (SELECT date, value1, value2,
                   (value2 * value1) AS value_calculated
            FROM . . . 
           ) t
     ) t

【讨论】:

    【解决方案2】:

    在其他 Stack Overflow 问题/响应中,CROSS APPLY 出现了。这对我不起作用,因为我需要创建 10-20 个计算列(所有这些列都引用其他计算列)。

    CROSS APPLY 可以被链接:

    SELECT t.*, s1.val1, s2.val2, s3.val3
    FROM tab t
    CROSS APPLY (SELECT t.val1 * t.val2 AS val3 FROM dual) s1
    CROSS APPLY (SELECT s1.val3 * 100   AS val4 FROM dual) s2
    CROSS APPLY (SELECT s2.val4 * 1000  AS val5 FROM dual) s3
    --...
    

    您只需要确保以正确的顺序引用对象。

    相关:

    How to use a calculated column to calculate another column in the same view

    【讨论】:

    • 谢谢!非常有帮助,我认为这将解决我的困境。我正在使用 WITH 子句,并加入两个表。我想我会做的是,加入两个表,然后使用另一个 WITH 子句来执行 CROSS APPLY,我需要添加 10-20 计算。它认为这会很完美,非常感谢。
    • 您能否澄清一下您上面的代码中的“双”表是什么?你已经在 CROSS 中申请了 FROM 双表。 @Lukasz Szozda
    • 如果使用 CROSS APPLY 方法,我尝试从 s1 和 tab t 引用计算列,我得到重复值。我应该包含一个 WHERE 语句并将 s1、s2、s3 表设置为彼此相等以进行内部连接吗?即 s1.id = t.id?我也会发布一些示例代码和输出。谢谢你的帮助。这个太棒了。 @Lukasz Szozda
    • @JesseNicholson Oracle SQL 语法需要 'from' 子句。因此提供了系统虚拟表dual,以便您可以高效地select from
    • @Lukasz Szozda,非常抱歉,我没看懂双表!我应该听从你的第一个指示。这似乎正在工作!我将发布最终代码以显示输出。太感谢了!!!!!!!这将用于数百人运行 Oracle 云报告的生产代码,谢谢,非常感谢! @William Robertson——谢谢你的介入和澄清,我想我明白了。稍后将发布最终代码并将此帖子归类为已解决!希望这对其他人也有帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-12-25
    • 2013-10-11
    • 2010-12-23
    • 2021-07-15
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多