Usando um alias em uma cláusula ONDE
Pergunta
Eu tenho uma consulta que se destina a me mostrar quaisquer linhas na tabela A, que não foram atualizados recentemente o suficiente. (Cada linha deve ser atualizada no prazo de 2 meses após "month_no".):
SELECT A.identifier
, A.name
, TO_NUMBER(DECODE( A.month_no
, 1, 200803
, 2, 200804
, 3, 200805
, 4, 200806
, 5, 200807
, 6, 200808
, 7, 200809
, 8, 200810
, 9, 200811
, 10, 200812
, 11, 200701
, 12, 200702
, NULL)) as MONTH_NO
, TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A
, table_b B
WHERE A.identifier = B.identifier
AND MONTH_NO > UPD_DATE
A última linha na cláusula WHERE causa um erro "ORA-00904 inválido Identifier". Escusado será dizer, eu não quero repetir toda a função DECODE em minha cláusula WHERE. Alguma ideia? (Ambas as correções e soluções alternativas aceite ...)
Solução
Isto não é possível diretamente, porque cronologicamente, ONDE acontece antes SELECT, que sempre é o último passo na cadeia de execução.
Você pode fazer um sub-select e filtro sobre ele:
SELECT * FROM
(
SELECT A.identifier
, A.name
, TO_NUMBER(DECODE( A.month_no
, 1, 200803
, 2, 200804
, 3, 200805
, 4, 200806
, 5, 200807
, 6, 200808
, 7, 200809
, 8, 200810
, 9, 200811
, 10, 200812
, 11, 200701
, 12, 200702
, NULL)) as MONTH_NO
, TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A
, table_b B
WHERE A.identifier = B.identifier
) AS inner_table
WHERE
MONTH_NO > UPD_DATE
pouco interessante de informações mudou-se a partir dos comentários:
Não deve haver nenhum impacto na performance. A Oracle não precisa se materializar consultas internas antes de aplicar exterior condições - Oracle vai considerar transformando essa consulta interna e empurrar para baixo o predicado para o interior consulta e vai fazê-lo se ele é custo eficaz. - Justin Caverna
Outras dicas
SELECT A.identifier
, A.name
, TO_NUMBER(DECODE( A.month_no
, 1, 200803
, 2, 200804
, 3, 200805
, 4, 200806
, 5, 200807
, 6, 200808
, 7, 200809
, 8, 200810
, 9, 200811
, 10, 200812
, 11, 200701
, 12, 200702
, NULL)) as MONTH_NO
, TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A, table_b B
WHERE .identifier = B.identifier
HAVING MONTH_NO > UPD_DATE
Ou você pode ter seu alias em uma cláusula HAVING
Assim como uma abordagem alternativa para que você pode fazer:
WITH inner_table AS
(SELECT A.identifier
, A.name
, TO_NUMBER(DECODE( A.month_no
, 1, 200803
, 2, 200804
, 3, 200805
, 4, 200806
, 5, 200807
, 6, 200808
, 7, 200809
, 8, 200810
, 9, 200811
, 10, 200812
, 11, 200701
, 12, 200702
, NULL)) as MONTH_NO
, TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A
, table_b B
WHERE A.identifier = B.identifier)
SELECT * FROM inner_table
WHERE MONTH_NO > UPD_DATE
Além disso, você pode criar uma vista permanente para o seu fila e selecionar a partir de vista.
CREATE OR REPLACE VIEW_1 AS (SELECT ...);
SELECT * FROM VIEW_1;
É possível definir de forma eficaz uma variável que pode ser usado tanto no SELECT, WHERE e outras cláusulas.
A subconsulta não necessariamente permitir a ligação adequada às colunas da tabela referenciadas, no entanto EXTERIOR APLICAR faz.
SELECT A.identifier
, A.name
, vars.MONTH_NO
, TO_NUMBER(TO_CHAR(B.last_update_date, 'YYYYMM')) as UPD_DATE
FROM table_a A
, table_b B ON A.identifier = B.identifier
OUTER APPLY (
SELECT
-- variables
MONTH_NO = TO_NUMBER(DECODE( A.month_no
, 1, 200803
, 2, 200804
, 3, 200805
, 4, 200806
, 5, 200807
, 6, 200808
, 7, 200809
, 8, 200810
, 9, 200811
, 10, 200812
, 11, 200701
, 12, 200702
, NULL))
) vars
WHERE vars.MONTH_NO > UPD_DATE
Kudos para Syed Mehroz Alam .