L'utilisation d'un alias dans une clause WHERE
Question
J'ai une question qui est censé me montrer toutes les lignes dans le tableau A qui n'a pas été mis à jour assez récemment. (Chaque ligne doit être mis à jour dans les 2 mois aprè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
La dernière ligne de la clause WHERE provoque une erreur « ORA-00904 Identifiant non valide ». Inutile de dire que je ne veux pas répéter l'ensemble de la fonction DECODE dans ma clause WHERE. Des pensées? (Les deux corrections et des solutions de contournement acceptés ...)
La solution
Ce n'est pas possible directement, parce que chronologiquement, Où se passe avant SELECT, ce qui est toujours la dernière étape de la chaîne d'exécution.
Vous pouvez faire une sous-sélection et filtrer sur elle:
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
Intéressant peu d'information est passé de commentaires:
Il devrait y avoir aucun impact sur les performances. Oracle n'a pas besoin de se matérialiser les requêtes internes avant d'appliquer extérieure conditions - Oracle envisageront transformant cette requête en interne et pousser le prédicat vers le bas dans l'intérieur interroger et il le fera si elle est le coût efficace. - Cave Justin
Autres conseils
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 vous pouvez avoir votre alias dans une clause de HAVING
Tout comme une approche alternative que vous pouvez faire:
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
Vous pouvez également créer une vue permanente pour votre file d'attente et sélectionnez la vue.
CREATE OR REPLACE VIEW_1 AS (SELECT ...);
SELECT * FROM VIEW_1;
Il est possible de définir efficacement une variable qui peut être utilisé dans les deux SELECT, WHERE et d'autres clauses.
Une sous-requête ne permet pas nécessairement de liaison appropriée aux colonnes de la table référencée, mais OUTER APPLY fait.
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 à Syed Alam Mehroz .