SQL JOIN between A, B and C mixing full and left join - sql

I'd like to know if there is a better way to create my left join in the below example:
SELECT TOP 10 COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
COALESCE(A.COD_FAMILY, B.COD_FAMILY),
COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
A.MASS
B.VOLUME
C.PRICE
FROM FIRSTTABLE A FULL JOIN SECONDTABLE B ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE C ON C.COD_PRODUCT = COALESCE(A.COD_PRODUCT,B.COD_PRODUCT)
AND C.COD_FAMILY = COALESCE(A.COD_FAMILY, B.COD_FAMILY)
AND C.DATE_EXTRACT = COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT)
That kind of jointure takes long time and I suspect it to be highly expensive and improvable
EDIT: I'd like to improve this SELECT FROM JOIN statement in a View.

You could split the query into two: gather all data matching FIRSTTABLE. And then union it with all data matching SECONDTABLE that is not in FIRSTTABLE.
That should allow SQL Server to use the indexes on these tables better.
SELECT A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
B.VOLUME,
C.PRICE
FROM FIRSTTABLE A
LEFT OUTER JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT OUTER JOIN THIRDTABLE C
ON C.COD_PRODUCT = A.COD_PRODUCT
AND C.COD_FAMILY = A.COD_FAMILY
AND C.DATE_EXTRACT = A.DATE_EXTRACT
UNION ALL
SELECT B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL AS MASS,
B.VOLUME,
C.PRICE
FROM SECONDTABLE B
LEFT OUTER JOIN THIRDTABLE C
ON C.COD_PRODUCT = B.COD_PRODUCT
AND C.COD_FAMILY = B.COD_FAMILY
AND C.DATE_EXTRACT = B.DATE_EXTRACT
WHERE NOT EXISTS (SELECT 1
FROM FIRSTTABLE A
WHERE A.COD_PRODUCT = B.COD_PRODUCT
AND A.COD_FAMILY = B.COD_FAMILY
AND A.DATE_EXTRACT = B.DATE_EXTRACT)

Compare the execution plan with this replacement join:
LEFT JOIN THIRDTABLE C
ON (C.COD_PRODUCT = A.COD_PRODUCT or C.COD_PRODUCT = B.COD_PRODUCT)
AND (C.COD_FAMILY = A.COD_FAMILY or C.COD_FAMILY = B.COD_FAMILY)
AND (C.DATE_EXTRACT =A.DATE_EXTRACT or C.DATE_EXTRACT = B.DATE_EXTRACT)

You might can achieve the same result with a UNION or UNION ALL
WITH cte AS (
SELECT
A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
NULL as VOLUME
FROM
FIRSTTABLE A
UNION
SELECT
B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL,
B.VOLUME
FROM
FIRSTTABLE A
)
SELECT
*
FROM
cte AB
LEFT JOIN
THIRDTABLE C ON C.COD_PRODUCT = AB.COD_PRODUCT
AND C.COD_FAMILY = AB.COD_FAMILY
AND C.DATE_EXTRACT = AB.DATE_EXTRACT
If you can have Mass and Volume for the product,family,extract combination you can use aggregate to join A and B together
WITH cte AS (
SELECT
COD_PRODUCT,
COD_FAMILY,
DATE_EXTRACT,
MAX(MASS) MASS,
MAX(VOLUME) VOLUME
FROM (
SELECT
A.COD_PRODUCT,
A.COD_FAMILY,
A.DATE_EXTRACT,
A.MASS,
NULL as VOLUME
FROM
FIRSTTABLE A
UNION ALL
SELECT
B.COD_PRODUCT,
B.COD_FAMILY,
B.DATE_EXTRACT,
NULL,
B.VOLUME
FROM
FIRSTTABLE A
) T
GROUP BY
COD_PRODUCT,
COD_FAMILY,
DATE_EXTRACT
)
SELECT
*
FROM
cte AB
LEFT JOIN
THIRDTABLE C ON C.COD_PRODUCT = AB.COD_PRODUCT
AND C.COD_FAMILY = AB.COD_FAMILY
AND C.DATE_EXTRACT = AB.DATE_EXTRACT

You can try this:
--- isolate the full join data from a and b into a temp table
SELECT
COD_PRODUCT= COALESCE(A.COD_PRODUCT, B.COD_PRODUCT),
COD_FAMILY= COALESCE(A.COD_FAMILY, B.COD_FAMILY),
DATE_EXTRACT= COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT),
MASS= A.MASS,
VOLUME= B.VOLUME
INTO #TEMP
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
-- add index clustered onto table (covering index)
CREATE CLUSTERED INDEX ix_tempCIndex ON #Temp ([COD_PRODUCT],[COD_FAMILY],[DATE_EXTRACT],[MASS],[VOLUME]);
-- left join C to this temp table
SELECT TOP 10
T.*, C.PRICE
FROM #TEMP T
LEFT JOIN THIRDTABLE C
ON C.COD_PRODUCT = T.COD_PRODUCT
AND C.COD_FAMILY = T.COD_FAMILY
AND C.DATE_EXTRACT = T.DATE_EXTRACT
-- drop temp table
DROP TABLE #TEMP

A coalesce or an OR inside of a join is going to slow down the query a lot. Depending on the size of the table, a better answer might be to join to table c twice. Once on table a and again on table B, then coalesce inside of your select clause.
SELECT TOP 10 COALESCE(A.COD_PRODUCT, B.COD_PRODUCT,c.COD_PRODUCT,ca.COD_PRODUCT),
COALESCE(A.COD_FAMILY, B.COD_FAMILY,c.COD_FAMILY,ca.COD_FAMILY),
COALESCE(A.DATE_EXTRACT, B.DATE_EXTRACT,c.DATE_EXTRACT,ca.DATE_EXTRACT),
A.MASS
B.VOLUME
C.PRICE
FROM FIRSTTABLE A
FULL JOIN SECONDTABLE B
ON B.COD_PRODUCT = A.COD_PRODUCT
AND B.COD_FAMILY = A.COD_FAMILY
AND B.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE C
ON C.COD_PRODUCT = A.COD_PRODUCT
AND C.COD_FAMILY = A.COD_FAMILY
AND C.DATE_EXTRACT = A.DATE_EXTRACT
LEFT JOIN THIRDTABLE Ca
ON Ca.COD_PRODUCT = b.COD_PRODUCT
AND Ca.COD_FAMILY = b.COD_FAMILY
AND Ca.DATE_EXTRACT = b.DATE_EXTRACT

Related

Retrieving available titles in full outer join of 4 tables

I need to consolidate the output of 4 different attribute tables. All tables have different row count. Currently I have this query:
CREATE VIEW vw_Items
AS
SELECT a.Countryname
,a.Itemname
,ISNULL(a.Colour,'None') as Colour
,ISNULL(b.Location,0) as Location
,ISNULL(c.Size,0) as Size
,ISNULL(d.Weight,0) as Weight
FROM ItemColour a
FULL OUTER JOIN ItemLocation b
ON a.Countryname = b.Countryname
AND a.Itemname= b.Itemname
FULL OUTER JOIN ItemSize c
ON a.Countryname = c.Countryname
AND a.Itemname= c.Itemname
FULL OUTER JOIN ItemWeight d
ON a.Countryname = d.Countryname
AND a.Itemname= d.Itemname
So, the issue is with NULL countryname and Itemname in table a, for which I think I need to do a nested CASE, but is there a better way to handle this?
Thank you.
I suspect you might want:
SELECT ci.Countryname, ci.Itemname
COALESCE(c.Colour, 'None') as Colour,
COALESCE(l.Location, 0) as Location
COALESCE(s.Size, 0) as Size
COALESCE(w.Weight, 0) as Weight
FROM ((SELECT c.countryname, c.itemname
FROM ItemColour c
) UNION -- on purpose to remove duplicates
(SELECT l.countryname, l.itemname
FROM ItemLocation c
) UNION
(SELECT s.countryname, s.itemname
FROM ItemSize
) UNION
(SELECT w.countryname, w.itemname
FROM ItemWeight w
)
) ci LEFT JOIN
ItemColor c
ON c.countryname = ci.countryname AND
c.itemname = ci.itemname LEFT JOIN
ItemLocation l
ON l.countryname = ci.countryname AND
l.itemname = ci.itemname LEFT JOIN
ItemSize s
ON s.countryname = ci.countryname AND
s.itemname = ci.itemname LEFT JOIN
ItemWeight w
ON w.countryname = ci.countryname AND
w.itemname = ci.itemname ;

Select two statements in one view

I have View called VW_STOCKOPNAME
CREATE OR REPLACE VIEW VW_STOCKOPNAME AS SELECT
A.M_STOCKCODE_KL_ID,
A.M_STOCKCODE_JB_ID,
A.M_STOCKCODE_NB_ID,
A.M_STOCKCODE_SB_ID,
B."NAME" AS S1_KL,
C."NAME" AS S2_JB,
D."NAME" AS S3_NB,
E."NAME" AS S4_SB,
A.M_ASSETCODE_GOLONGAN_ID,
A.M_ASSETCODE_BIDANG_ID,
A.M_ASSETCODE_KELOMPOK_ID,
A.M_ASSETCODE_SUBKELOMPOK_ID,
A.M_ASSETCODE_SUBSUBKEL_ID,
F."NAME" AS A1_GOLONGAN,
G."NAME" AS A2_BIDANG,
H."NAME" AS A3_KELOMPOK,
I."NAME" AS A4_SUBKELOMPOK,
J."NAME" AS A5_SUBSUBKEL,
A.M_PRODUCT_ID,
K."NAME" AS PRODUCT,
L."NAME" AS UOM,
A.QTYBOOK,
A.QTYCOUNT,
A.DIFFERENCE,
N.M_WAREHOUSE_ID,
O."NAME" AS WAREHOUSE
FROM M_INVENTORYLINE A
LEFT JOIN M_STOCKCODE_KL B ON B.M_STOCKCODE_KL_ID = A.M_STOCKCODE_KL_ID
LEFT JOIN M_STOCKCODE_JB C ON C.M_STOCKCODE_JB_ID = A.M_STOCKCODE_JB_ID
LEFT JOIN M_STOCKCODE_NB D ON D.M_STOCKCODE_NB_ID = A.M_STOCKCODE_NB_ID
LEFT JOIN M_STOCKCODE_SB E ON E.M_STOCKCODE_SB_ID = A.M_STOCKCODE_SB_ID
LEFT JOIN M_ASSETCODE_GOLONGAN F ON F.M_ASSETCODE_GOLONGAN_ID = A.M_ASSETCODE_GOLONGAN_ID
LEFT JOIN M_ASSETCODE_BIDANG G ON G.M_ASSETCODE_BIDANG_ID = A.M_ASSETCODE_BIDANG_ID
LEFT JOIN M_ASSETCODE_KELOMPOK H ON H.M_ASSETCODE_KELOMPOK_ID = A.M_ASSETCODE_KELOMPOK_ID
LEFT JOIN M_ASSETCODE_SUBKELOMPOK I ON I.M_ASSETCODE_SUBKELOMPOK_ID = A.M_ASSETCODE_SUBKELOMPOK_ID
LEFT JOIN M_ASSETCODE_SUBSUBKEL J ON J.M_ASSETCODE_SUBSUBKEL_ID = A.M_ASSETCODE_SUBSUBKEL_ID
LEFT JOIN M_PRODUCT K ON K.M_PRODUCT_ID = A.M_PRODUCT_ID
LEFT JOIN C_UOM L ON L.C_UOM_ID = A.C_UOM_ID
LEFT JOIN M_INVENTORY N ON N.M_INVENTORY_ID = A.M_INVENTORY_ID
LEFT JOIN M_WAREHOUSE O ON O.M_WAREHOUSE_ID = N.M_WAREHOUSE_ID
;
I want to add another column which has command as follows :
SELECT S1_KL ||'-'|| S2_JB ||'-'|| S3_NB ||'-'|| S4_SB AS ASSET_CODE
FROM VW_STOCKOPNAME
It shows group of codes from the columns in the view to make it easier to see.
How can I add it?
Try this
CREATE OR REPLACE VIEW VW_STOCKOPNAME AS SELECT
A.M_STOCKCODE_KL_ID,
A.M_STOCKCODE_JB_ID,
A.M_STOCKCODE_NB_ID,
A.M_STOCKCODE_SB_ID,
B."NAME" AS S1_KL,
C."NAME" AS S2_JB,
D."NAME" AS S3_NB,
E."NAME" AS S4_SB,
A.M_ASSETCODE_GOLONGAN_ID,
A.M_ASSETCODE_BIDANG_ID,
A.M_ASSETCODE_KELOMPOK_ID,
A.M_ASSETCODE_SUBKELOMPOK_ID,
A.M_ASSETCODE_SUBSUBKEL_ID,
F."NAME" AS A1_GOLONGAN,
G."NAME" AS A2_BIDANG,
H."NAME" AS A3_KELOMPOK,
I."NAME" AS A4_SUBKELOMPOK,
J."NAME" AS A5_SUBSUBKEL,
A.M_PRODUCT_ID,
K."NAME" AS PRODUCT,
L."NAME" AS UOM,
A.QTYBOOK,
A.QTYCOUNT,
A.DIFFERENCE,
N.M_WAREHOUSE_ID,
O."NAME" AS WAREHOUSE,
B."NAME" ||'-'|| C."NAME" ||'-'|| D."NAME" ||'-'|| E."NAME" AS ASSET_CODE
FROM M_INVENTORYLINE A
LEFT JOIN M_STOCKCODE_KL B ON B.M_STOCKCODE_KL_ID = A.M_STOCKCODE_KL_ID
LEFT JOIN M_STOCKCODE_JB C ON C.M_STOCKCODE_JB_ID = A.M_STOCKCODE_JB_ID
LEFT JOIN M_STOCKCODE_NB D ON D.M_STOCKCODE_NB_ID = A.M_STOCKCODE_NB_ID
LEFT JOIN M_STOCKCODE_SB E ON E.M_STOCKCODE_SB_ID = A.M_STOCKCODE_SB_ID
LEFT JOIN M_ASSETCODE_GOLONGAN F ON F.M_ASSETCODE_GOLONGAN_ID = A.M_ASSETCODE_GOLONGAN_ID
LEFT JOIN M_ASSETCODE_BIDANG G ON G.M_ASSETCODE_BIDANG_ID = A.M_ASSETCODE_BIDANG_ID
LEFT JOIN M_ASSETCODE_KELOMPOK H ON H.M_ASSETCODE_KELOMPOK_ID = A.M_ASSETCODE_KELOMPOK_ID
LEFT JOIN M_ASSETCODE_SUBKELOMPOK I ON I.M_ASSETCODE_SUBKELOMPOK_ID = A.M_ASSETCODE_SUBKELOMPOK_ID
LEFT JOIN M_ASSETCODE_SUBSUBKEL J ON J.M_ASSETCODE_SUBSUBKEL_ID = A.M_ASSETCODE_SUBSUBKEL_ID
LEFT JOIN M_PRODUCT K ON K.M_PRODUCT_ID = A.M_PRODUCT_ID
LEFT JOIN C_UOM L ON L.C_UOM_ID = A.C_UOM_ID
LEFT JOIN M_INVENTORY N ON N.M_INVENTORY_ID = A.M_INVENTORY_ID
LEFT JOIN M_WAREHOUSE O ON O.M_WAREHOUSE_ID = N.M_WAREHOUSE_ID
;

SQL Query - Using Information From One Inquiry In Another

Here is my query. I removed the table names along with other things I am selecting just to make it easier to read.
Select
b.Key1,
b.Key2
From
b
left join c
on c.MailingKey = b.MailingKey
left join d
on d.OrderLineKey = c.OrderLineKey
left join e
on e.ShipKey = d.ShipKey
left join g
on d.ShipKey5 = g.ShipKey5
left join a
on a.DocKey = b.OrderKey
left join f
on f.pMethKey = b.MethKey
I need to use Key1 and Key2 that I select in another query to get more information about that key (location, ID, etc.) from another table. I am thinking I will need to make 2 loops within this original query and join them all up. So something like this:
Select b.Key1, b.Key2, h.*, i.*
From b left join
c on c.MailingKey = b.MailingKey left join
d on d.OrderLineKey = c.OrderLineKey left join
e on e.ShipKey = d.ShipKey left join
g on d.ShipKey5 = g.ShipKey5 left join
a on a.DocKey = b.OrderKey left join
f on f.pMethKey = b.MethKey left join
(
Select*
From table l
Where ID = b.Key1
) h left join (
Select*
From table l
Where ID = b.Key2
) i
I am just not sure how to write equal to b.Key1 and b.Key2.
I am using Microsoft Sql Server Management.
Common table expression:
with cte as (
Select b.Key1, b.Key2
From b left join
c on c.MailingKey = b.MailingKey left join
d on d.OrderLineKey = c.OrderLineKey left join
e on e.ShipKey = d.ShipKey left join
g on d.ShipKey5 = g.ShipKey5 left join
a on a.DocKey = b.OrderKey left join
f on f.pMethKey = b.MethKey)
Select * from CTE
INNER JOIN othertable o
on b.key1=o.key1
and b.key2=o.key2
or do you mean...
Inline view:
Select *
from otherTable
INNER JOIN (
Select b.Key1, b.Key2
From b left join
c on c.MailingKey = b.MailingKey left join
d on d.OrderLineKey = c.OrderLineKey left join
e on e.ShipKey = d.ShipKey left join
g on d.ShipKey5 = g.ShipKey5 left join
a on a.DocKey = b.OrderKey left join
f on f.pMethKey = b.MethKey) CTE
on b.key1=o.key1
and b.key2=o.key2
Or do you mean.... something else?
Perhaps:... using an OR statement...
Select *
from otherTable o
INNER JOIN (
Select b.Key1, b.Key2
From b left join
c on c.MailingKey = b.MailingKey left join
d on d.OrderLineKey = c.OrderLineKey left join
e on e.ShipKey = d.ShipKey left join
g on d.ShipKey5 = g.ShipKey5 left join
a on a.DocKey = b.OrderKey left join
f on f.pMethKey = b.MethKey) CTE
on o.key1=cte.key1
OR o.key2=cte.key2
or maybe... an in statement (within this set)
Select *
from otherTable o
INNER JOIN (
Select b.Key1, b.Key2
From b left join
c on c.MailingKey = b.MailingKey left join
d on d.OrderLineKey = c.OrderLineKey left join
e on e.ShipKey = d.ShipKey left join
g on d.ShipKey5 = g.ShipKey5 left join
a on a.DocKey = b.OrderKey left join
f on f.pMethKey = b.MethKey) CTE
on o.key1 IN (cte.key1, cte.key2)

SQL select distinct entity - union all - order by another entity's column

I am using SQL to access an entity (Forslag), but would also like to sort using another entity's column (b.dato).
This is my initial SQL:
select distinct ff.*
from Forslag ff
inner join Forlag f on ff.forlag_id = f.forlag_id
inner join LoggBehandling b on ff.forlag_id = b.forlag_id
inner join Kontrollpanel p on f.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
union all
select distinct ft.*
from Forslag ft
inner join Tidsskrift t on ft.tidsskrift_id = t.tidsskrift_id
inner join LoggBehandling b on ft.tidsskrift_id = b.tidsskrift_id
inner join Kontrollpanel p on t.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
order by b.dato desc
Hibernate complains: ORDER BY items must appear in the select list if the statement contains a UNION, INTERSECT or EXCEPT operator.
I suspect I can't really add b.dato to select, as I assume this will have impact on the mapping:
select distinct ff.*, b.dato
from Forslag ff
inner join Forlag f on ff.forlag_id = f.forlag_id
inner join LoggBehandling b on ff.forlag_id = b.forlag_id
inner join Kontrollpanel p on f.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
union all
select distinct ft.*, b.dato
from Forslag ft
inner join Tidsskrift t on ft.tidsskrift_id = t.tidsskrift_id
inner join LoggBehandling b on ft.tidsskrift_id = b.tidsskrift_id
inner join Kontrollpanel p on t.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
order by b.dato desc
How should I solve this?
are you sure is HQL and not SQL???
The first: in HQL is not possible using UNION ALL but you must execute two distinct queries.
The second: in SQL when you use an order by when you have an UNION operation, you must apply ORDER BY to result table in this way:
The third: Why you use DISTINCT if you use UNION ALL?? Use UNION without ALL is the same thing of DISTINCT.
select *
from (
select ff.*, b.dato as dato
from Forslag ff
inner join Forlag f on ff.forlag_id = f.forlag_id
inner join LoggBehandling b on ff.forlag_id = b.forlag_id
inner join Kontrollpanel p on f.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
union all
select distinct ft.*, b.dato
from Forslag ft
inner join Tidsskrift t on ft.tidsskrift_id = t.tidsskrift_id
inner join LoggBehandling b on ft.tidsskrift_id = b.tidsskrift_id
inner join Kontrollpanel p on t.uhrPuMote_id = p.saksbehandlerUhrPuMote_id
where b.status_id = 7
) as resultTable
order by resultTable.dato desc

Could use advice in making my query smarter

Hi Guys I have the following query but the unions make it quite heavy so could anyone help in fixing my query.
There are 3 scenarios.
1. pack_no = pack of an item (inside packitem)
2. item = item inside pack (inside packitem)
3. item = doesn't have pack (inside item_master)
SELECT DISTINCT item, loc FROM
(SELECT e.pack_no item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no) AND d.item = e.pack_no
WHERE d.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' AND f.sh_trade_unit = 'Y')
UNION
SELECT e.item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no)
WHERE e.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' AND f.sh_trade_unit = 'Y')
UNION
SELECT d.item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
WHERE d.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' and f.sh_trade_unit = 'Y')
);
The simplest way to improve the performance of the query would be to change the UNIONs to UNION ALLs - that way, the query only has to eliminate duplicates once.
However, it should be possible to simplify this query to:
WITH CTE AS
(SELECT d.item d_item, e.item e_item, e.pack_no e_pack_no, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no)
)
SELECT DISTINCT item, loc FROM
(--SELECT e_pack_no item, loc FROM CTE WHERE d_item = e_pack_no UNION ALL -- this select is a subset of the third select
SELECT e_item item, loc FROM CTE UNION ALL
SELECT d_item item, loc FROM CTE) uc
WHERE uc.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' and f.sh_trade_unit = 'Y')