Updating a Java sql query from UNION to JOIN - sql

I have the following query,
table PCA and PC have similar structure (same columns).
select session, wc, sum(duration) / (sum(delta) + sum(duration)) as wc_efficiency from
(
SELECT
a.session, a.panel,
a.line_location as WC,
a.line_duration as duration,
a.line_lead_duration - b.line_lead_duration as delta
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.line_location is not null
union
SELECT
a.session, a.panel,
a.completion_location as WC2,
a.completion_duration as duration2,
a.completion_lead_duration - b.completion_lead_duration as delta2
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.completion_location is not null
)
group by session, wc
Now, I want to find wc2 & wc_efficiency2 disjointedly for duration2 & delta2 as separate columns. To achieve that I update my queries as follows:
select session, wc1, sum(duration1) / (sum(delta1) + sum(duration1)) as wc_efficiency1, wc2, sum(duration2) / (sum(delta2) + sum(duration2)) as wc_efficiency2 from
(
SELECT
a.session as ss, a.panel as pl,
a.line_location as WC1,
a.line_duration as duration1,
a.line_lead_duration - b.line_lead_duration as delta1
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.line_location is not null
) t1
join
(
SELECT
a.session as ss, a.panel as pl,
a.completion_location as WC2,
a.completion_duration as duration2,
a.completion_lead_duration - b.completion_lead_duration as delta2
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.completion_location is not null
) t2
ON t1.ss = t2.ss and t1.pl = t2.pl
group by wc1, wc2
The query does not run, I can't find the error.

Related

Any alternate of REGEXP_LIKE as it causing performance issue

We have one sql which is performing bad.I have fixed the execution plan but REGEXP_LIKE causing high buffer gets and also contribute in runtime.Any alternate which i can use in my sql.The problematc is
AND REGEXP_LIKE (xx3la.assembly_type, '^I..*')
/* Formatted on 1/6/2023 2:07:28 PM (QP5 v5.318) */
SELECT 1
FROM apps.oe_order_lines_all ola
JOIN APPS.OE_order_headers_all oh
ON oh.Header_Id = ola.header_id AND oh.org_id = ola.org_id
JOIN inv.mtl_parameters org
ON ola.ship_from_org_id = org.ORGANIZATION_ID
INNER JOIN ont.oe_transaction_types_tl tt
ON tt.transaction_type_id = oh.order_type_id
AND tt.language = 'US'
AND LPAD (UPPER (tt.name), 4) NOT IN ('TRIA',
'WARR',
'REPA',
'DUMM',
'DEMO',
'GOOD',
'INTE',
'CRED',
'EVAL',
'INVO') --- ('STAND')
JOIN apps.mtl_system_items_b msib
ON ola.Ordered_item_Id = msib.inventory_item_id
AND msib.ORGANIZATION_ID = org.ORGANIZATION_ID
INNER JOIN xxom.xxom_3lp_sym_ora_order_hdr xx3ha
ON xx3ha.header_id = oh.header_id
INNER JOIN xxom.xxom_3lp_sym_ora_order_lines xx3la
ON xx3la.header_id = ola.header_id AND xx3la.line_id = ola.line_id
LEFT JOIN
(SELECT msib.Inventory_item_id,
mcb.segment1 ProductionLine,
msib.ORGANIZATION_ID,
msib.item_type,
msib.Fixed_LEAD_Time
FROM apps.mtl_system_items_b msib
JOIN inv.mtl_parameters org
ON msib.ORGANIZATION_ID = org.ORGANIZATION_ID
JOIN apps.MTL_ITEM_CATEGORIES ic
ON ic.INVENTORY_ITEM_ID = msib.INVENTORY_ITEM_ID
AND msib.organization_id = ic.ORGANIZATION_ID
JOIN apps.mtl_categories_b mcb
ON mcb.CATEGORY_ID = ic.CATEGORY_ID
WHERE mcb.ENABLED_FLAG = 'Y' AND ic.CATEGORY_SET_ID = 1100009407) im
ON ola.Ordered_item_Id = im.inventory_item_id
AND org.organization_id = im.organization_id
LEFT JOIN ( SELECT Header_Id,
Line_Id,
WIP_ORDER_NUMBER,
MAX (PRODUCT_LINE) PRODUCT_LINE
FROM XXRMT.XXURD_SO_UNIT
GROUP BY Header_Id, Line_Id, WIP_ORDER_NUMBER) u
ON u.Header_Id = oh.Header_Id AND u.Line_Id = ola.Line_Id
LEFT JOIN wip.wip_discrete_jobs wdj
ON wdj.source_line_id = ola.line_id
AND wdj.status_type IN (1,
2,
3,
4,
5,
12)
LEFT JOIN wip.wip_entities we ON we.wip_entity_id = wdj.wip_entity_id
LEFT JOIN xxrmt.xxont_som_scheduler adm
ON adm.subscriber_id = xx3la.order_admin
LEFT JOIN apps.oe_order_lines_all ol2
ON ol2.ato_line_id = ola.line_id
AND ol2.item_type_code IN ('CONFIG')
LEFT JOIN
(SELECT mso.source_organization_code,
mso.vendor_name,
mso.vendor_site,
msa.sourcing_rule_name,
DECODE (mso.source_type,
1, 'TRANSFER',
2, 'MAKE',
3, 'BUY')
SourceType,
msa.inventory_item_id,
msa.organization_id
FROM apps.mrp_sr_assignments_v msa
--join inv.mtl_parameters org on msa.organization_id = org.organization_id
INNER JOIN apps.mrp_sourcing_rules msr
ON msr.sourcing_rule_id = msa.sourcing_rule_id
INNER JOIN apps.mrp_sr_receipt_org_v msro
ON msr.sourcing_rule_id = msro.sourcing_rule_id
INNER JOIN apps.mrp_sr_source_org_v mso
ON mso.sr_receipt_id = msro.sr_receipt_id AND mso.RANK = 1
WHERE msa.assignment_set_id = 561
AND (msro.disable_date IS NULL OR disable_date >= SYSDATE))
srd
ON srd.inventory_item_id = ol2.inventory_item_id
AND srd.organization_id = ola.ship_from_org_id
WHERE org.organization_code IN ('DRM')
AND ola.Flow_Status_Code <> 'CANCELLED'
AND NVL (oh.Cancelled_flag, 'N') = 'N'
AND oh.Flow_Status_Code <> 'CANCELLED'
AND ola.booked_flag = 'Y'
AND oh.booked_date IS NOT NULL
AND TRUNC (oh.booked_date) >= TO_DATE ('2022-12-01', 'YYYY-MM-DD')
AND msib.item_type NOT IN ('P',
'B/R',
'OP',
'SVC',
'OP',
'EMR_PURCH')
AND ( ola.item_type_code IN ('CONFIG', 'MODEL')
OR ( ola.item_type_code IN ('CLASS')
AND REGEXP_LIKE (xx3la.assembly_type, '^I..*'))
OR ( ola.item_type_code IN ('CLASS')
AND u.PRODUCT_LINE IS NOT NULL
AND xx3la.model_string IS NOT NULL
AND msib.segment1 NOT IN ('R-CAP1199', 'R-38-315'))
OR ( ola.item_type_code = 'STANDARD'
AND xx3la.assembly_type IS NULL))
Somehow fixed the BG issue but still REGEXP_LIKE an issue
Your current regex assertion:
REGEXP_LIKE(xx3la.assembly_type, '^I..*')
can be written using an ordinary LIKE:
xx3la.assembly_type LIKE 'I_%'
Note that the above LIKE version should be able to use an index on assembly_type. That being said, I doubt that the REGEXP_LIKE call be the only major performance bottleneck existing in a query of this size and complexity. You should run EXPLAIN on your query to view the execution plan.

Group by Month Using a Column That has Daily Dates

I need to add in an extra 'group by' field to the below code to group by Month in relation to the trade_date field. The code currently results in a table with column headers matching the 4 fields in the beginning 'select' statement. I need to add a 5th that uses the trade_date field to group by month, not day. Any thoughts?
select
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL
FROM
(
SELECT
a.transaction_id,
b.amount,
b.charge_id,
c.charge_type_id,
d.charge_group,
e.account_name,
f.sig_entity_label,
e.trading_userid,
e.exchange_id,
e.tradeable_instr_name,
g.instr_subtype_label,
g.underlying_sym_bloomberg,
g.fut_expiration_date,
e.trade_date,
timestamp_table.timeformated,
a.rate * a.basis_value AS dma_fee,
SUM(A.RATE * A.BASIS_VALUE) OVER () as DMA_FEE_TOTAL
FROM
repldoadm.ire_estimate_trans_map a
LEFT JOIN repldoadm.ire_charges_estimate b ON a.estimate_id = b.estimate_id
LEFT JOIN repldoadm.ire_charges_lu c ON b.charge_id = c.charge_id
LEFT JOIN repldoadm.ire_charge_types_lu d ON c.charge_type_id = d.charge_type_id
LEFT JOIN repldoadm.vw_ire_trade_transactions e ON a.transaction_id = e.trans_id
LEFT JOIN (
SELECT
to_char(create_ts, 'HH24:MI:SS') AS timeformated,
trans_id
FROM
repldoadm.vw_ire_trade_transactions
) timestamp_table ON ( a.transaction_id = timestamp_table.trans_id )
LEFT JOIN repldoadm.vw_ire_accounts f ON e.account_name = f.pb_account_name
LEFT JOIN stig_adm.instrument_universe g ON e.tradeable_instr_name = g.short_name
WHERE
timeformated >= '07:00:00'
AND timeformated <= '18:00:00'
AND fut_expiration_date >= add_months(trunc(sysdate), - 12)
AND trade_date = '02-AUG-21'
AND e.exchange_id = '30'
AND charge_group = 'EXECUTION_BROKER_CHARGES'
AND estimate_run = 'Late'
--AND transaction_id IN ( '791088074', '791309067' )
)
group by TRADEABLE_INSTR_NAME, TRADING_USERID, UNDERLYING_SYM_BLOOMBERG;
Group by TRUNC(trade_date, 'MM')
SELECT TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL,
TRUNC( trade_date, 'MM' ) AS trade_month
FROM (
<your huge sub-query>
)
group by
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM');
Your query would effectively be:
select TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM') AS trade_month
SUM(DMA_FEE) AS DMA_FEE_SUBTOTAL
FROM (
SELECT e.trading_userid,
e.tradeable_instr_name,
g.underlying_sym_bloomberg,
e.trade_date,
a.rate * a.basis_value AS dma_fee
FROM repldoadm.ire_estimate_trans_map a
INNER JOIN repldoadm.ire_charges_estimate b
ON a.estimate_id = b.estimate_id
INNER JOIN repldoadm.ire_charges_lu c
ON b.charge_id = c.charge_id
INNER JOIN repldoadm.ire_charge_types_lu d
ON c.charge_type_id = d.charge_type_id
INNER JOIN repldoadm.vw_ire_trade_transactions e
ON ( a.transaction_id = e.trans_id
AND TO_CHAR(e.create_ts, 'HH24:MI:SS') BETWEEN '07:00:00'
AND '18:00:00'
)
LEFT JOIN repldoadm.vw_ire_accounts f
ON e.account_name = f.pb_account_name
INNER JOIN stig_adm.instrument_universe g
ON e.tradeable_instr_name = g.short_name
WHERE g.fut_expiration_date >= add_months(trunc(sysdate), - 12)
AND e.trade_date = DATE '2021-08-02'
AND e.exchange_id = '30'
AND d.charge_group = 'EXECUTION_BROKER_CHARGES'
AND estimate_run = 'Late'
--AND transaction_id IN ( '791088074', '791309067' )
)
group by
TRADEABLE_INSTR_NAME,
TRADING_USERID,
UNDERLYING_SYM_BLOOMBERG,
TRUNC(trade_date, 'MM');
Note: Because you are requiring non-NULL values in the WHERE clause your LEFT JOINs become INNER JOINs.
Note: You do not need to SELECT columns in the inner query that you are not using in the outer query.
Note: I do not know if you need to join repldoadm.vw_ire_accounts f as you do not appear to use it.

Probably subquerys and not joins

This big query below returns me 2860 records and its correct number. I'm getting. The thing is that I need to add to this query invoice lines and make the same thing as I did with sale_order_lines "sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) AS price_subtotal". I need to get the sum of price_subtotal of invoice lines.
so my first thought was to join tables like this.
JOIN sale_order_invoice_rel so_inv_rel on (so_inv_rel.order_id = s.id )
JOIN account_invoice inv on (inv.id = so_inv_rel.invoice_id and inv.state in ('open','paid'))
JOIN account_invoice_line ail on (inv.id = ail.invoice_id)
and then
sum(ail.price_subtotal / COALESCE(cr.rate, 1.0)) as price_subtotal
but after the first JOIN number of lines, I'm selecting is changing and even if I joins are done the numbers are way off basically I get 5x2860. So probably I need to make some subquery but at this point, I don't know how and asking for help.
WITH currency_rate AS (
SELECT r.currency_id,
COALESCE(r.company_id, c.id) AS company_id,
r.rate,
r.name AS date_start,
( SELECT r2.name
FROM res_currency_rate r2
WHERE r2.name > r.name AND r2.currency_id = r.currency_id AND (r2.company_id IS NULL OR r2.company_id = c.id)
ORDER BY r2.name
LIMIT 1) AS date_end
FROM res_currency_rate r
JOIN res_company c ON r.company_id IS NULL OR r.company_id = c.id
)
SELECT min(l.id) AS id,
l.product_id,
l.color_id,
l.product_size_id,
t.uom_id AS product_uom,
sum(l.product_uom_qty / u.factor * u2.factor) AS product_uom_qty,
sum(l.qty_delivered / u.factor * u2.factor) AS qty_delivered,
sum(l.qty_invoiced / u.factor * u2.factor) AS qty_invoiced,
sum(l.qty_to_invoice / u.factor * u2.factor) AS qty_to_invoice,
sum(l.price_total / COALESCE(cr.rate, 1.0)) AS price_total,
l.price_unit / COALESCE(cr3.rate, 1.0) AS price_total_by_cmp_curr,
sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) AS price_subtotal,
count(*) AS nbr,
s.date_order AS date,
s.state,
s.partner_id,
s.user_id,
s.company_id,
date_part('epoch'::text, avg(date_trunc('day'::text, s.date_order) - date_trunc('day'::text, s.create_date))) / (24 * 60 * 60)::numeric(16,2)::double precision AS delay,
t.categ_id,
s.pricelist_id,
s.project_id AS analytic_account_id,
s.team_id,
p.product_tmpl_id,
partner.country_id,
partner.commercial_partner_id
FROM sale_order_line l
JOIN sale_order s ON l.order_id = s.id
JOIN res_partner partner ON s.partner_id = partner.id
LEFT JOIN product_product p ON l.product_id = p.id
LEFT JOIN product_template t ON p.product_tmpl_id = t.id
LEFT JOIN product_uom u ON u.id = l.product_uom
LEFT JOIN product_uom u2 ON u2.id = t.uom_id
LEFT JOIN res_company rc ON rc.id = s.company_id
LEFT JOIN product_pricelist pp ON s.pricelist_id = pp.id
LEFT JOIN currency_rate cr ON cr.currency_id = pp.currency_id AND cr.company_id = s.company_id AND cr.date_start <= COALESCE(s.date_order::timestamp with time zone, now()) AND (cr.date_end IS NULL OR cr.date_end > COALESCE(s.date_order::timestamp with time zone, now()))
LEFT JOIN currency_rate cr3 ON cr.currency_id = rc.currency_id AND cr.company_id = s.company_id AND cr.date_start <= COALESCE(s.date_order::timestamp with time zone, now()) AND (cr.date_end IS NULL OR cr.date_end > COALESCE(s.date_order::timestamp with time zone, now()))
GROUP BY l.product_id, t.uom_id, t.categ_id, s.date_order, s.partner_id, s.user_id, s.state, s.company_id, s.pricelist_id, s.project_id, s.team_id, l.color_id, cr3.rate, l.price_unit, l.product_size_id, p.product_tmpl_id, partner.country_id, partner.commercial_partner_id;
You can add the part that could be in a subquery to the with statement you already have to avoid the increase in number of lines, like so:
WITH currency_rate AS (
SELECT r.currency_id,
COALESCE(r.company_id, c.id) AS company_id,
r.rate,
r.name AS date_start,
( SELECT r2.name
FROM res_currency_rate r2
WHERE r2.name > r.name AND r2.currency_id = r.currency_id AND (r2.company_id IS NULL OR r2.company_id = c.id)
ORDER BY r2.name
LIMIT 1) AS date_end
FROM res_currency_rate r
JOIN res_company c ON r.company_id IS NULL OR r.company_id = c.id
)
, order_line_subtotal AS(
SELECT so_inv_rel.order_id, sum(ail.price_subtotal) as price_subtotal
FROM sale_order_invoice_rel so_inv_rel
JOIN account_invoice inv on (inv.id = so_inv_rel.invoice_id and inv.state in ('open','paid'))
JOIN account_invoice_line ail on (inv.id = ail.invoice_id)
GROUP BY so_inv_rel.order_id )
SELECT min(l.id) AS id,
....
From there it should be straightforward to add to the query without increasing the number of rows (since from the joins you already have a row for each order before the aggregation / group by.

SQL sum and subtract issue with two queries

OK, I need somehelp. I have the following two queries:
SELECT DA.OWNG_OCD AS OFFICE, 'FL' AS STATE, SUM(S.STK_END_SEQ_NUM -
S.STK_STRT_SEQ_NUM) + COUNT(*) AS TOTSTK FROM STKRNG S, DFACCT DA, CMPNT C
WHERE RANGE_USED_SW = 'N' AND S.DFTACCT_CANUM = DA.DFTACCT_CANUM
AND DA.OWNG_OCD = C.OCD AND C.ST = 'FL' AND S.STK_TYP = 'R' GROUP
BY DA.OWNG_OCD;
AND
SELECT C.OCD, COUNT(*) AS USED FROM DRAFT D
JOIN STKRNG S ON S.DFTACCT_CANUM = D.DFTACCT_CANUM
JOIN DFACCT DA ON S.DFTACCT_CANUM = DA.DFTACCT_CANUM
JOIN CMPNT C ON CMPNT.OCD = DA.OWNG_OCD
WHERE D.DRFT_SEQ_NUM >= (SELECT MIN(S.STK_STRT_SEQ_NUM) FROM STKRNG S
WHERE D.DFTACCT_CANUM = S.DFTACCT_CANUM AND S.RANGE_USED_SW = 'N')
AND D.DRFT_SEQ_NUM <= (SELECT MAX(S.STK_END_SEQ_NUM) FROM STKRNG S WHERE
D.DFTACCT_CANUM = S.DFTACCT_CANUM AND S.RANGE_USED_SW = 'N')
AND S.STK_TYP = 'R'
AND S.RANGE_USED_SW = 'N'
AND C.ST = 'FL'
GROUP BY C.OCD;
I am trying to write one query where the results of the COUNT in the second query are subtracted from the results of the COUNT in the first query. Any idea on how to do this?
Put your queries in the from clause of your final query:
select q1.totstk - q2.used
from ( <your first query here> ) q1
join ( <your second query here> ) q2 on q2.ocd = q1.office;
try Something like this:
with STKRNGMINMAX as (
SELECT S.DFTACCT_CANUM,
MIN(S.STK_STRT_SEQ_NUM) MINNUM, MAX(S.STK_END_SEQ_NUM) MAXNUM,
SUM(S.STK_END_SEQ_NUM - S.STK_STRT_SEQ_NUM) DIFFNUM
FROM STKRNG S
WHERE (S.RANGE_USED_SW, S.STK_TYP)=('N', 'R')
group by S.DFTACCT_CANUM
)
SELECT C.OCD, S.DIFFNUM - COUNT(*) AS TOTSTK,
FROM DRAFT D
INNER JOIN STKRNGMINMAX S ON S.DFTACCT_CANUM = D.DFTACCT_CANUM and D.DRFT_SEQ_NUM between S.MINNUM AND S.MAXNUM
INNER JOIN DFACCT DA ON S.DFTACCT_CANUM = DA.DFTACCT_CANUM
INNER JOIN CMPNT C ON C.OCD = DA.OWNG_OCD and C.ST='FL'
GROUP BY C.OCD;

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