4

Oracle SQLで動的に計算するいくつかの列を再利用しようとしています。

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

「tablename」には「A」という列がありますが、他の列はありません。これは私に

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管理者ではないことに注意してください:(。


更新:より具体的なクエリを使用した実際の例。私がやりたいことは次のとおりです。

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」も選択したいと思います (これは、このクエリをサブクエリ/with-clause として使用できるようになりました)。


更新: わかりました。今のところ、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 は補正項です。

4

6 に答える 6

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

これは、最も読みやすく、保守可能で、フォローしやすいバージョンです。

UPDATE の場合、column_name = 表記を使用した非推奨の SQL Server 回避策があり、リスト内で以前に更新された列を参照できます。ただし、これは SELECT では使用できません。

将来のある時点で、(スカラー UDF を使用せずに) 式をスタックする機能が ANSI SQL に追加されることを願っています。

于 2009-04-13T13:46:19.887 に答える
0

あなたがこれを行うことができるかどうかはわかりませんが(私はそれが行われるのを見たことがありません)、あなたはそれを回避することができます:

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

これは、サブクエリを導入するよりも確かに優れています。

私が提案する他の唯一の方法は、少なくともクエリのテキストを単純化するP / Qタイプの列を(上記の式を使用して)提供するビューを作成することです。次に、次のことができます。

SELECT P, Q FROM viewintotablename
于 2009-04-13T12:40:12.417 に答える
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

、これはより効率的で(EXPそしてLOGコストがかかり)、デバッグがはるかに簡単です。

于 2009-04-13T12:46:35.833 に答える
0

SQL でこれを行う直接的な方法はありません。

ただし、PL/SQL を使用して関数を定義することはできます。だからあなたの選択はこのようになります

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

P と Q の場合、これはオリジナルよりも (はるかに) 優れているわけではありませんが、関数が複雑で、多くのパラメーターを必要としない場合は、ステートメントがはるかに読みやすくなる可能性があります。

また、SQL ステートメントやデータから独立して関数をテストすることもできます。

于 2009-04-13T12:57:47.180 に答える
0

あなたが与えたインラインビューの例よりも、これが少し好きかもしれません:

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

同じことになりますが、読みやすくなっていると思います。

計算列が複数の列で使用されるものである場合は、永続的なビューを作成することが理にかなっている場合があります。

Oracle 11 (私はまだ使用していません) には、便利な仮想列機能があります。

于 2009-04-13T13:03:01.520 に答える