简体   繁体   中英

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

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.

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 (+)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM