Home > Software design >  oracle subquery problem with rownum and order by in where clause invalid identifier for outer table
oracle subquery problem with rownum and order by in where clause invalid identifier for outer table

Time:07-02

I'm trying to find a way to resolve an sql query. I want to do a subquery to select enable articles for a product id in first. In fact i'm working on a part of a query. I would want just one article for a product the last enable or else the last disable if no enable articles. The problem is that i was asked to not use join with request without join at first. It's legacy app.

Here is a working example :

from T_PRODUIT pro, T_PRODUIT_PLATEFORME_EXTENDED pre, T_ARTICLE art, T_TAUX_TVA tva
where pro.id_produit = 1330442 
and art.id_article in (select id_article from T_ARTICLE ta where ta.id_produit = pro.id_produit and ta.id_fournisseur = pre.id_fournisseur_article) 
and pro.ID_PRODUIT = pre.ID_PRODUIT
and pre.ID_PRODUIT = art.ID_PRODUIT( )
and pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR( )
and tva.CODE = pro.ID_TVA

and what i would want :

  from T_PRODUIT pro, T_PRODUIT_PLATEFORME_EXTENDED pre, T_ARTICLE art, T_TAUX_TVA tva
    where pro.id_produit = 1330442 
    and art.id_article in (select * from (select id_article from T_ARTICLE ta where ta.id_produit     = pro.id_produit and ta.id_fournisseur = pre.id_fournisseur_article order by ta.actif DESC) where rownum < 2)
    and pro.ID_PRODUIT = pre.ID_PRODUIT
    and pre.ID_PRODUIT = art.ID_PRODUIT( )
    and pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR( )
    and tva.CODE = pro.ID_TVA

The problem with the second example is that there are two nesting level and pro and pre are invalid identifiers in this case. Someone know how i can bypass this problem ? The database sometimes contains strange rows causing complex sql. Thanks.

CodePudding user response:

From Oracle 12, you can use the FETCH FIRST ROW ONLY syntax:

from   T_PRODUIT pro
       INNER JOIN T_PRODUIT_PLATEFORME_EXTENDED pre
       ON (pro.ID_PRODUIT = pre.ID_PRODUIT)
       LEFT OUTER JOIN T_ARTICLE art
       ON (   pre.ID_PRODUIT = art.ID_PRODUIT
          AND pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR)
       INNER JOIN T_TAUX_TVA tva
       ON (tva.CODE = pro.ID_TVA)
WHERE  pro.id_produit = 1330442 
AND    art.id_article in ( select id_article
                           from    T_ARTICLE ta
                           where   ta.id_produit     = pro.id_produit
                           and     ta.id_fournisseur = pre.id_fournisseur_article 
                           order by ta.actif DESC
                           FETCH FIRST ROW ONLY
                         )

Note: You may want to move that IN filter condition to the ON clause of the join so that it is part of the outer join condition; otherwise you are effectively converting the OUTER JOIN to an INNER JOIN.

In earlier versions you can use:

from   T_PRODUIT pro
       INNER JOIN T_PRODUIT_PLATEFORME_EXTENDED pre
       ON (pro.ID_PRODUIT = pre.ID_PRODUIT)
       LEFT OUTER JOIN T_ARTICLE art
       ON (   pre.ID_PRODUIT = art.ID_PRODUIT
          AND pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR)
       INNER JOIN T_TAUX_TVA tva
       ON (tva.CODE = pro.ID_TVA)
WHERE  pro.id_produit = 1330442 
AND    art.id_article in ( select ta.id_article
                           from    (
                             SELECT id_produit,
                                    id_fournisseur,
                                    id_article
                             FROM   T_ARTICLE
                             order by actif DESC
                           ) ta
                           where   ta.id_produit     = pro.id_produit
                           and     ta.id_fournisseur = pre.id_fournisseur_article
                           and     ROWNUM < 2
                         )

Note: again, you may want to move it into the join condition.

However, what you probably want is:

from   T_PRODUIT pro
       INNER JOIN T_PRODUIT_PLATEFORME_EXTENDED pre
       ON (pro.ID_PRODUIT = pre.ID_PRODUIT)
       LEFT OUTER JOIN (
         SELECT ta.*,
                ROW_NUMBER() OVER (
                  PARTITION BY ID_PRODUIT, ID_FOURNISSEUR
                  ORDER     BY actif DESC
                ) AS rn
         FROM   T_ARTICLE ta
       ) art
       ON (   pre.ID_PRODUIT = art.ID_PRODUIT
          AND pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR
          AND art.rn = 1)
       INNER JOIN T_TAUX_TVA tva
       ON (tva.CODE = pro.ID_TVA)
WHERE  pro.id_produit = 1330442

Or, using the legacy joins:

from   T_PRODUIT pro,
       T_PRODUIT_PLATEFORME_EXTENDED pre,
       (
         SELECT ta.*,
                ROW_NUMBER() OVER (
                  PARTITION BY ID_PRODUIT, ID_FOURNISSEUR
                  ORDER     BY actif DESC
                ) AS rn
         FROM   T_ARTICLE ta
       ) art,
       T_TAUX_TVA tva
WHERE  pro.id_produit             = 1330442
AND    pro.ID_PRODUIT             = pre.ID_PRODUIT
AND    tva.CODE                   = pro.ID_TVA
AND    pre.ID_PRODUIT             = art.ID_PRODUIT ( )
AND    pre.ID_FOURNISSEUR_ARTICLE = art.ID_FOURNISSEUR ( )
AND    1                          = art.rn ( )
  • Related