2009-04-13 54 views
4

我嘗試重用一些列我在甲骨文SQL動態計算,像如何在Oracle SQL語句中重用動態列?

SELECT 
    A*2 AS P, 
    P+5 AS Q 
FROM tablename 

其中「表名」有一個名爲「A」柱,但沒有其他colums。這給了我一個

ORA-00904: "P": invalid identifier 

我知道如何解決這個使用子查詢像

SELECT P, P+5 AS Q 
FROM (SELECT A*2 AS P FROM tablename) 

但我認爲這是有點醜。此外,我想讓查詢更復雜些,例如重用'Q',我不想創建另一個子查詢。

更新:我想存儲'P'的計算的原因是我想讓它更復雜,並重復使用'P'多次。所以我不想明確地說'A * 2 + 5 AS Q',因爲這會很快變得麻煩,因爲'P'變得更加複雜。

必須有一個很好的方法來做到這一點,任何想法?

更新:我要指出,我不是一個DB-管理員:(


更新:A現實世界的例子,有一個更具體的查詢,我想什麼做的是:

SELECT 
    SL/SQRT(AB) AS ALPHA, 
    5*LOG(10,ALPHA) AS B, 
    2.5*LOG(10,1-EXP(-5/ALPHA)*(5/ALPHA+1)) AS D 
    BS -2.74 + B + D AS BSA 
FROM tablename 

現在,我已經寫了出來,它的工作原理,但醜:

SELECT 
    SL/SQRT(AB) AS ALPHA, 
    5*LOG(10,SL/SQRT(AB)) AS B, 
    2.5*LOG(10,1-EXP(-5/(SL/SQRT(AB)))*(5/(SL/SQRT(AB))+1)) AS D 
    BS -2.74 + 5*LOG(10,SL/SQRT(AB)) + 2.5*LOG(10,1-EXP(-5/(SL/SQRT(AB)))*((5/(SL/SQRT(AB)))+1)) AS BSA 
FROM tablename 

接收到數據後,我能做到這一切,但我想,讓我們看看如何我可以讓數據庫做很多事情。另外,我想選擇'BSA'(我現在可以使用這個查詢作爲子查詢/帶子句)。


更新:好的,我想現在我已經完成了Cade Roux'和Dave Costa的解決方案。雖然Pax'和Jens Schauder的解決方案看起來會更好,但由於我不是DBA,所以我無法使用它們。現在我不知道該標記爲最佳答案:)。

WITH 
    A1 AS ( 
    SELECT A0.*, 
    SL/SQRT(AB) AS ALPHA 
    FROM tablename A0 
), 
    A2 AS (
    SELECT A1.*, 
    5*LOG(10,ALPHA) AS B, 
    2.5*LOG(10,1-EXP(-5/ALPHA)*((5/ALPHA)+1)) AS D 
    FROM A1 
) 
SELECT 
    ALPHA, B, D, BS, 
    BS -2.74 + B + D AS BSA 
FROM A2 

順便說一句,如果任何人的愛好,SB是星系的「表面亮度」,爲此,B和d是校正項。

回答

2

我們在SQL Server中有這個相同的問題(這是一個ANSI問題)。我相信這是爲了避免混淆混疊效應:

SELECT A * 2 AS A 
    ,A * 3 AS B -- This is the original A, not the new A 
FROM whatever 

我們解決它通過堆疊起來公用表表達式:

WITH A1 AS (
    SELECT A * 2 AS A 
    FROM whatever 
) 
,A2 AS (
    SELECT A1.* 
     ,A * 3 AS B 
    FROM A1 
) 
,A3 AS (
    SELECT A2.* 
     ,A + B AS X 
    FROM A2 
) 
SELECT * 
FROM A3 

這是最可讀的,maintable和隨動版本。

對於UPDATE,有一個不推薦的SQL Server解決方法,使用column_name = notation,您可以在其中引用列表中以前已更新的列。但是這不能用於SELECT。

我希望在未來的某個時候,將一些堆棧表達式(不使用標量UDF)的能力添加到ANSI SQL中。

0

我不知道你能做到這一點(我從來沒有見過它做),但你可以解決它:

SELECT 
    A*2 AS P, 
    A*2+5 AS Q 
FROM tablename 

這當然不是引進子查詢更好。

我建議的唯一方法是創建一個視圖,爲您提供P/Q類型列(使用上面的公式),這至少可以簡化查詢的文本。那麼你可以:

SELECT P, Q FROM viewintotablename 
+0

是的,這是有效的,我在示例中的查詢變得簡單,實際上我多次使用P值來計算其他列,而P則更加複雜。我會更新這個問題。 – BlackShift 2009-04-13 12:42:53

+0

我不完全確定你爲什麼如此關心查詢。他們傾向於寫一次,然後單獨留下,所以它們真的很「醜」(假設真正醜陋的那些被正確記錄:-)。 – paxdiablo 2009-04-13 12:49:40

+0

我曾經認識的DBA需要關注的* only *事情是原始速度,如果不進行反規範化(即,將生成的列引入到DB2),我認爲您不會輕鬆修復它。 – paxdiablo 2009-04-13 12:50:11

0

你不能。

如果不希望子查詢重新評估呢,添加一絲NO_MERGE爲子查詢:

此子查詢將在嵌套循環被重新評估(用於MERGE提示):

SELECT /*+ LEADING(g) USE_NL(g, r) MERGE(g) */ 
     * 
FROM (
     SELECT 1 
     FROM dual 
     UNION ALL 
     SELECT 2 
     FROM dual 
     ) r, 
     (
     SELECT SYS_GUID() AS guid 
     FROM dual d 
     ) g 

--- 
33CA48C1AB6B4403808FB0219302CE43 
711BB04F9AFC406ABAEF8A8F4CFA1266 

此子查詢不會在嵌套循環被重新評估(NO_MERGE提示使用):

SELECT /*+ LEADING(g) USE_NL(g, r) NO_MERGE(g) */ 
     * 
FROM (
     SELECT 1 
     FROM dual 
     UNION ALL 
     SELECT 2 
     FROM dual 
     ) r, 
     (
     SELECT SYS_GUID() AS guid 
     FROM dual d 
     ) g 

------ 
7715C69698A243C0B379E68ABB55C088 
7715C69698A243C0B379E68ABB55C088 

在你的情況下,強制未寫:

SELECT BS - 2.74 + d 
FROM (
     SELECT t2.*, 2.5 * LOG(10, 1 - EXP(-5/b)) * ((5/A) + 1) AS d 
     FROM (
       SELECT t1.*, 5 * LOG(10, alpha) AS b 
       FROM (
         SELECT /*+ NO_MERGE */ t.*, 
           SL/SQRT(AB) AS alpha 
         FROM tablename t 
         ) t1 
       ) t2 
     ) t3 

,這是更有效的(EXPLOG是昂貴的),並且是更易於調試。

0

在sql中沒有直接的方法來做到這一點。

但是你可以使用PL/SQL定義一個函數。所以,你的選擇是這樣的

select 
    P(A), 
    Q(P(A)) 
from tablename 

對於P和Q這不是(多)優於原來的,但如果功能是複雜的,並且沒有很多的參數,它可能使你的聲明更具可讀性。

它還允許您獨立於sql語句和任何數據測試函數。

0

你可能會喜歡比你給的內嵌視圖例如更好這一點:

WITH inner_view AS (SELECT A*2 AS P FROM tablename) 
SELECT P, P+5 AS Q 
FROM inner_view 

它相當於同樣的事情,但它是一個更清晰一點看,我想。

如果計算列是您將在多列中使用的東西,則創建永久視圖可能有意義。

Oracle 11(我還沒有用過)具有虛擬列功能,可能對您有用。