Как повторно использовать динамические столбцы в операторе Oracle SQL? - PullRequest
4 голосов
/ 13 апреля 2009

Я пытаюсь повторно использовать некоторые столбцы, которые я вычисляю динамически в 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» станет более сложным.

Должен быть хороший способ сделать это, есть идеи?

Обновление: я должен отметить, что я не администратор БД: (.


Обновление: пример из реальной жизни с более конкретным запросом. То, что я хотел бы сделать, это:
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 выглядело бы лучше, но я не могу их использовать, так как я не администратор баз данных. Теперь я не знаю, кого пометить как лучший ответ:).

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. - поправочные члены.

Ответы [ 6 ]

2 голосов
/ 13 апреля 2009

У нас такая же проблема в 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

Это самая читаемая, удобная и понятная версия.

Для ОБНОВЛЕНИЙ существует устаревший обходной путь SQL Server с использованием нотации column_name =, где вы можете ссылаться на столбец, который был ранее обновлен в списке. Но это не может быть использовано в SELECT.

Я хотел бы надеяться, что некоторая возможность составлять выражения (без использования скалярной UDF) будет добавлена ​​к ANSI SQL в какой-то момент в будущем.

0 голосов
/ 21 апреля 2019

Повторное использование псевдонимов часто встречается в Teradata, однако иногда это может привести к путанице, главным образом, когда вы создаете псевдоним столбца с именем, которое существует в таблице / подзапросе, и пытаетесь использовать его повторно, база данных будет использовать исходный столбец, а не тот, который вы используете. алиас.

0 голосов
/ 13 апреля 2009

Возможно, вам понравится это немного лучше, чем приведенный пример встроенного просмотра:

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

Это то же самое, но, кажется, немного понятнее.

Если вычисляемый столбец - это то, что вы будете использовать в нескольких столбцах, возможно, имеет смысл создать постоянное представление.

Oracle 11 (который я еще не использовал) имеет функцию виртуальных столбцов, которая может быть полезна для вас.

0 голосов
/ 13 апреля 2009

Нет прямого способа сделать это в sql.

Но вы можете определить функцию, используя PL / SQL. Таким образом, ваш выбор будет выглядеть так

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

Для P и Q это не намного лучше оригинала, но если функции сложны и не имеют большого количества параметров, это может сделать ваше утверждение намного более читабельным.

Это также позволит вам протестировать ваши функции независимо от оператора SQL и любых данных.

0 голосов
/ 13 апреля 2009

Вы не можете.

Если вы не хотите, чтобы подзапрос был переоценен, добавьте подсказку 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 являются дорогостоящими) и намного проще в отладке.

0 голосов
/ 13 апреля 2009

Я не уверен, что вы можете сделать это (я никогда не видел, чтобы это было сделано), но вы можете обойти это с помощью:

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

Это, конечно, лучше, чем вводить подзапрос.

Единственный другой способ, который я бы предложил, - это создать представление с колонками типа P / Q (используя формулы выше), которые, по крайней мере, упростили бы текст запроса. Тогда вы могли бы просто:

SELECT P, Q FROM viewintotablename
...