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