How to replace the OR condition in the Oracle SQL query? - oracle

I am using Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Can somebody please tell me how to rewrite the below cursor query so that
it does not use the "OR" clause in the where condition
for performance benefits.
Basically the OR condition should be removed appropriately in the query.
CURSOR c_picklist_dtl IS
SELECT DISTINCT pd.dc_code,
pd.storer,
pd.picklist_key,
pd.pickdetail_key,
pd.line_no,
pd.pick_type,
pd.case_id,
pd.order_type,
pd.sub_type,
pd.order_no,
pd.item,
pd.consignee,
pd.bin_code,
pd.lot,
pd.pallet_id,
pd.packkey,
pd.to_pick_qty,
am.bin_code dispatch_bin_code,
ph.wave_id,
ph.po_no,
pd.pick_area_type,
pd.assignment_id,
pd.pick_method,
pd.pack_method,
pd.ord_priority,
pd.pick_seq_no
FROM table1 ph,
table2 pd,
table3 ot,
table4 am
WHERE pd.dc_code = ph.dc_code
AND pd.storer = ph.storer
AND pd.picklist_key = ph.picklist_key
AND ph.dc_code = p_dc_code
AND ph.storer = p_storer
AND ( ( ph.po_no = p_order_no
AND p_order_prefix = 'X'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
OR ( ph.wave_id = p_order_no
AND p_order_prefix = 'W'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
)
AND pd.item = p_item
AND pd.consignee = p_consignee
AND pd.dc_code = ot.dc_code
AND pd.order_type = ot.order_type
AND pd.sub_type = ot.sub_type
AND am.dc_code(+) = ot.dc_code
AND am.dc_area(+) = ot.dispatch_area
AND pd.to_pick_qty > 0
ORDER BY pd.dc_code,
pd.item,
pd.consignee,
pd.pick_seq_no,
pd.pickdetail_key,
pd.line_no;
Thanks

Your OR clause is pretty much the same apart from one literal comparison and different matching column for one of the input parameters, which pretty much means you can replace:
AND ( ( ph.po_no = p_order_no
AND p_order_prefix = 'X'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
OR ( ph.wave_id = p_order_no
AND p_order_prefix = 'W'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
)
with just something like:
AND p_order_no = CASE WHEN p_order_prefix = 'X' THEN ph.po_no
WHEN p_order_prefix = 'W' THEN ph.wave_id
ELSE NULL
END
AND pd.pick_method = 'P'
AND pd.status = 'E'

You can avoid repeating the 2 tests which are the same.
To go further you need to know the application and understand the logic.
AND ( ( ph.po_no = p_order_no
AND p_order_prefix = 'X'
OR )
( ph.wave_id = p_order_no
AND p_order_prefix = 'W') )
AND pd.pick_method = 'P'
AND pd.status = 'E'
can replace
AND ( ( ph.po_no = p_order_no
AND p_order_prefix = 'X'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
OR ( ph.wave_id = p_order_no
AND p_order_prefix = 'W'
AND pd.pick_method = 'P'
AND pd.status = 'E'
)
)

Related

how to group oracle queries which has aggregate functions

it says "not a groupby function". when I add D.unitpricef to groupby it doesn't show any error,but in result it shows same itmcode multiple time. one item code should diplay only one time
SELECT
ItemCode,
case when H.InvoType = 1 then concat(ItemCode,' ( SLT Equipment )' ) else concat(ItemCode,' (
CONBES Eqipment )' ) end as EquName,
case when TRIM(SUM(QTY)) is null then '' else TRIM(TO_CHAR(SUM(QTY),'999999')) end as QTY,
CAST( (SUM(QTY) * D.unitpricef) AS NUMBER(38,2)) AS Amount
FROM Invoicedetails D
INNER JOIN
invoiceheader H ON D.InvoiceNo = H.InvoiceNo
INNER JOIN Equipment E ON E.EquCode = ItemCode
WHERE
H.CancelStat= 0
AND H.ReceiptStat = 1
AND H.BCCODE = 'xxx'
GROUP BY ItemCode,H.InvoType ORDER BY ItemCode ASC;
You need to group by using the same expressions associated to the aggregate function
SELECT
ItemCode,
case when H.InvoType = 1 then concat(ItemCode,' ( SLT Equipment )' ) else concat(ItemCode,' ( CONBES Eqipment )' ) end as EquName,
case when TRIM(SUM(QTY)) is null then '' else TRIM(TO_CHAR(SUM(QTY),'999999')) end as QTY,
CAST( (SUM(QTY) * D.unitpricef) AS NUMBER(38,2)) AS Amount
FROM Invoicedetails D
INNER JOIN
invoiceheader H ON D.InvoiceNo = H.InvoiceNo
INNER JOIN Equipment E ON E.EquCode = ItemCode
WHERE
H.CancelStat= 0
AND H.ReceiptStat = 1
AND H.BCCODE = 'xxx'
GROUP BY
ItemCode
case when H.InvoType = 1 then concat(ItemCode,' ( SLT Equipment )' ) else concat(ItemCode,' ( CONBES Eqipment )' ) end
ORDER BY ItemCode ASC;

I want to add a subquery with a date parameter to return a calculated value but my query is not working

I have a query that fetches data from oracle inventory and purchasing. Now I want to add a subquery from po_line_locations_all with a date parameter to return a calculated value as if the value lies in the subquery show it else display zero, But in my case the query shows nothing if subquery returns null.
I want to show the result of the main query even if subquery returns null.
SELECT distinct msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
SUM(plla.quantity) - SUM(plla.quantity_received) On_Order,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
(
SELECT SUM (moq.transaction_quantity)
FROM mtl_system_items_b msi, mtl_onhand_quantities moq
WHERE moq.organization_id(+) = msi.organization_id
AND moq.inventory_item_id(+) = msi.inventory_item_id
and moq.ORGANIZATION_ID =MSIB.organization_id
and msi.inventory_item_id = MSIB.inventory_item_id
GROUP BY msi.segment1, msi.organization_id
) CURR_STOCK,
(
SELECT NVL(ABS(sum(mtmt.transaction_quantity)),0) from MTL_MATERIAL_TRANSACTIONS mtmt
WHERE 1=1
AND mtmt.inventory_item_id = MSIB.inventory_item_id --4018
AND mtmt.organization_id = MSIB.organization_id--499
and mtmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
AND to_date(mtmt.transaction_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
)RB_TRANSACTIONS,
(
select ABS(SUM(mmt.transaction_quantity))
from MTL_MATERIAL_TRANSACTIONS mmt
where mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
and mmt.TRANSACTION_TYPE_ID in (33, 52)
)
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),'DD-MON-YYYY')
AND to_date(&CONS_f_DATE, 'DD-MON-YYYY')
)
AND (mmt.parent_transaction_id IS NULL)
) annual_Consumption,
(
select ABS(SUM(mmt.transaction_quantity) / 4)
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
AND mmt.TRANSACTION_TYPE_ID in (33, 52)
)
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),
'DD-MON-YYYY') AND
to_date(&CONS_f_DATE, 'DD-MON-YYYY'))
AND (mmt.parent_transaction_id IS NULL)
) months_Consumption,
(
select ABS((SUM(mmt.transaction_quantity) / 4) / 3)
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24, 30)
and (mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
)
and (mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
AND mmt.TRANSACTION_TYPE_ID in (33, 52))
and (mmt.transaction_date between
to_date(add_months(&CONS_f_DATE, -12),
'DD-MON-YYYY') AND
to_date(&CONS_f_DATE, 'DD-MON-YYYY'))
AND (mmt.parent_transaction_id IS NULL)
) monthly_Average,
(
select MATERIAL_COST
FROM CST_ITEM_COST_TYPE_V vw
WHERE vw.organization_id = MSIB.organization_id
AND - 1 = -1
and (vw.INVENTORY_ITEM_ID = MSIB.inventory_item_id)
) Unit_Cost, --new
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB,
PO_HEADERS_ALL ph,
Po_Lines_All pl,
PO_LINE_LOCATIONS_ALL PLLA,
-------------------SUBQUERY---------------------------------------
(select nvl(sum(subplla.quantity),0) t_quantity, nvl(sum(subplla.quantity_received),0) r_quantity ,subpl.item_id
from po_headers_all subph,
po_lines_all subpl,
po_line_locations_all subplla
where subph.po_header_id = subpl.po_header_id
and subplla.po_header_id = subph.po_header_id
and subpl.po_line_id = subplla.po_line_id
and subplla.org_id = subpl.org_id
and to_date(subplla.creation_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
group by subph.attribute1, subph.currency_code, subpl.item_id
) quan
-------------------SUBQUERY---------------------------------------
WHERE 1=1
and ph.po_header_id = pl.po_header_id
and msib.inventory_item_id (+) = pl.item_id
and pl.item_id (+) = quan.item_id
and plla.po_header_id = ph.po_header_id
and pl.po_line_id = plla.po_line_id
and plla.org_id = pl.org_id
and msib.organization_id in
(select haou.organization_id
from hr_organization_information hoi,
hr_all_organization_units haou
where haou.organization_id = hoi.organization_id
and hoi.org_information1 = 'INV'
and hoi.org_information2 = 'Y'
and haou.name like '%HEIS%')
and MSIB.Inventory_Item_Id=NVL(&ITEM,MSIB.Inventory_Item_Id)
and MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN
to_date(add_months(&Roll_back_date, -12),'DD-MON-YYYY') AND
to_date(&Roll_back_date,'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code
My guess is that your problem is simply using old-syntax joins instead of something that has been around for a really long time.
SELECT DISTINCT msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
SUM(plla.quantity) - SUM(plla.quantity_received) On_Order,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
(
SELECT SUM(moq.transaction_quantity)
FROM mtl_system_items_b msi
RIGHT JOIN mtl_onhand_quantities moq ON moq.organization_id = msi.organization_id
AND moq.inventory_item_id = msi.inventory_item_id
WHERE moq.ORGANIZATION_ID = MSIB.organization_id
AND msi.inventory_item_id = MSIB.inventory_item_id
GROUP BY msi.segment1,
msi.organization_id
) CURR_STOCK,
(
SELECT NVL(ABS(sum(mtmt.transaction_quantity)), 0)
FROM MTL_MATERIAL_TRANSACTIONS mtmt
WHERE 1 = 1
AND mtmt.inventory_item_id = MSIB.inventory_item_id --4018
AND mtmt.organization_id = MSIB.organization_id --499
AND mtmt.TRANSACTION_ACTION_ID NOT IN (24,30)
AND to_date(mtmt.transaction_date) >= to_date(&Roll_back_date, 'DD-MON-RRRR')
) RB_TRANSACTIONS,
mmt.annual_Consumption annual_Consumption,
mmt.annual_Consumption / 4 months_Consumption,
mmt.annual_Consumption / 12 monthly_Average,
(
SELECT MATERIAL_COST
FROM CST_ITEM_COST_TYPE_V vw
WHERE vw.organization_id = MSIB.organization_id
AND vw.INVENTORY_ITEM_ID = MSIB.inventory_item_id
) Unit_Cost, --new
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB
LEFT JOIN PO_HEADERS_ALL ph ON msib.inventory_item_id = pl.item_id
INNER JOIN Po_Lines_All pl ON ph.po_header_id = pl.po_header_id
INNER JOIN PO_LINE_LOCATIONS_ALL PLLA ON plla.po_header_id = ph.po_header_id AND pl.po_line_id = plla.po_line_id AND plla.org_id = pl.org_id
LEFT JOIN
-------------------SUBQUERY---------------------------------------
(
SELECT nvl(sum(subplla.quantity), 0) t_quantity,
nvl(sum(subplla.quantity_received), 0) r_quantity,
subpl.item_id
FROM po_headers_all subph
INNER JOIN po_lines_all subpl ON subph.po_header_id = subpl.po_header_id
INNER JOIN po_line_locations_all subplla ON subplla.po_header_id = subph.po_header_id
AND subpl.po_line_id = subplla.po_line_id
AND subplla.org_id = subpl.org_id
WHERE to_date(subplla.creation_date) >= to_date(&Roll_back_date, 'DD-MON-RRRR')
GROUP BY subph.attribute1,
subph.currency_code,
subpl.item_id
) quan ON pl.item_id = quan.item_id
-------------------SUBQUERY---------------------------------------
LEFT JOIN (
SELECT mmt.ORGANIZATION_ID,
mmt.INVENTORY_ITEM_ID,
ABS(SUM(mmt.transaction_quantity)) AS annual_Consumption
FROM MTL_MATERIAL_TRANSACTIONS mmt
WHERE mmt.TRANSACTION_ACTION_ID NOT IN (24,30)
AND mmt.TRANSACTION_TYPE_ID IN (33,52)
AND mmt.transaction_date BETWEEN to_date(add_months(&CONS_f_DATE, - 12), 'DD-MON-YYYY')
AND to_date(&CONS_f_DATE, 'DD-MON-YYYY')
AND mmt.parent_transaction_id IS NULL
) mmt ON mmt.ORGANIZATION_ID = MSIB.organization_id --499--579
AND mmt.INVENTORY_ITEM_ID = MSIB.inventory_item_id --4128 --4165
WHERE msib.organization_id IN (
SELECT haou.organization_id
FROM hr_organization_information hoi
JOIN hr_all_organization_units haou ON haou.organization_id = hoi.organization_id
WHERE hoi.org_information1 = 'INV'
AND hoi.org_information2 = 'Y'
AND haou.name LIKE '%HEIS%'
)
AND MSIB.Inventory_Item_Id = NVL(&ITEM, MSIB.Inventory_Item_Id)
AND MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN to_date(add_months(&Roll_back_date, - 12), 'DD-MON-YYYY')
AND to_date(&Roll_back_date, 'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code;
Here is the query in its simplest form, The main query is working good without the subquery. But when subquery returns null (i.e. no output in the date range) the whole query returns nothing. I want it to display results regardless the subquery results. My guess is something is wrong with the JOIN –
SELECT distinct msib.segment1 Item_Code,
MSIB.inventory_item_id,
MSIB.organization_id ORG_ID,
msib.description Item_Description,
msib.primary_unit_of_measure UOM,
ph.attribute1 Item_Type,
ph.currency_code currency,
max(pl.unit_price) FOB_Value_in_FCY,
max(ph.rate_date),
max(ph.rate) forex_rate,
sum(quan.t_quantity) - sum(r_quantity) finala
FROM mtl_system_items_b MSIB,
PO_HEADERS_ALL ph,
Po_Lines_All pl,
PO_LINE_LOCATIONS_ALL PLLA,
------------SUBQUERY-------------------------------
(select nvl(sum(subplla.quantity),0) t_quantity, nvl(sum(subplla.quantity_received),0) r_quantity ,subpl.item_id
from po_headers_all subph,
po_lines_all subpl,
po_line_locations_all subplla
where subph.po_header_id = subpl.po_header_id
and subplla.po_header_id = subph.po_header_id
and subpl.po_line_id = subplla.po_line_id
and subplla.org_id = subpl.org_id
and to_date(subplla.creation_date) >= to_date(&Roll_back_date,'DD-MON-RRRR')
group by subph.attribute1, subph.currency_code, subpl.item_id
) quan
------------SUBQUERY-------------------------------
WHERE 1=1
and ph.po_header_id = pl.po_header_id
and msib.inventory_item_id (+) = pl.item_id
-----------------joining subquery-------------------
and pl.item_id (+) = quan.item_id
-----------------joining subquery-------------------
and plla.po_header_id = ph.po_header_id
and pl.po_line_id = plla.po_line_id
and plla.org_id = pl.org_id
and msib.organization_id in
(select haou.organization_id
from hr_organization_information hoi,
hr_all_organization_units haou
where haou.organization_id = hoi.organization_id
and hoi.org_information1 = 'INV'
and hoi.org_information2 = 'Y'
and haou.name like '%HEIS%')
and MSIB.Inventory_Item_Id=NVL(&ITEM,MSIB.Inventory_Item_Id)
and MSIB.organization_id = nvl(&P_ORGI, MSIB.organization_id)
AND to_date(plla.creation_date) BETWEEN
to_date(add_months(&Roll_back_date, -12),'DD-MON-YYYY') AND
to_date(&Roll_back_date,'DD-MON-YYYY')
GROUP BY msib.segment1,
MSIB.inventory_item_id,
msib.description,
MSIB.organization_id,
msib.primary_unit_of_measure,
ph.attribute1,
ph.currency_code

How can I join these two select queries into one query?

this is my first time posting, so I am sure I will get a number of things wrong. Do not hesitate to correct me and I will do everything I can to clarify.
In Oracle SQL Developer, I am trying to take two separate SELECT statements and combine them to get one row of results. Unfortunately, because this is sensitive data, I am unable to give any results from the statements individually, but instead, just the SQL statements themselves. I suspect I should be able to join these two on the field "emplid" but just cannot get there. Any help is greatly appreciated! Here is the code below, please mind the syntax :)
1st Select statement is giving me a list of people that were paid in 2017:
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
And 2nd Select statement would be a list of the deductions taken for the employees that were identified in the first statement:
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
Ideally, what I'd like to do is put in a value in place of 'XXXXXX' and get one row of data with the two combined statements.
Thanks everyone!
To do this, we stick each SELECT statement into a subquery and give that subquery an alias to refer to in the main queries select statement:
SELECT t1.*, t2.*
FROM
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
) t1
INNER JOIN
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
) t2 ON
t1.empid = t2.empid
We just treat each derived table/subquery as it's own table and join them on empid. You can tweak the SELECT statement at the top as needed.
This is similar to creating a view for both sql statements and then referencing the views in a third sql statement.
An alternative way of doing this is to use CTE (Common Table Expressions) to house the separate sql. There's no performance advantage here, but you might find it easier to read.
WITH t1 as
(
SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
ORDER BY C.COMPANY, C.EMPLID
),
t2 AS
(
SELECT G.EMPLID, G.DEDCD,
CASE
WHEN DC.DED_CLASS IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "EEAmt",
CASE
WHEN DC.DED_CLASS NOT IN ('A','B','T')
THEN G.DED_ADDL_AMT
ELSE 0
END AS "ERAmt",
DC.DED_CLASS,
G.DED_ADDL_AMT,
G.GOAL_AMT
FROM PS_GENL_DEDUCTION G,
PS_DED_CLASS_VW DC
WHERE G.EFFDT =
(SELECT MAX(G_ED.EFFDT)
FROM PS_GENL_DEDUCTION G_ED
WHERE G.EMPLID = G_ED.EMPLID
AND G.COMPANY = G_ED.COMPANY
AND G.DEDCD = G_ED.DEDCD
AND G_ED.EFFDT <= SYSDATE
)
AND ( G.DEDUCTION_END_DT IS NULL
OR G.DEDUCTION_END_DT > SYSDATE)
AND ( G.GOAL_AMT = 0.00
OR G.GOAL_AMT <> G.GOAL_BAL)
AND G.DED_ADDL_AMT > 0
AND DC.PLAN_TYPE = '00'
AND DC.DEDCD = G.DEDCD
AND DC.EFFDT =
(SELECT MAX(V1.EFFDT)
FROM PS_DED_CLASS_VW V1
WHERE V1.PLAN_TYPE = DC.PLAN_TYPE
AND V1.DEDCD = DC.DEDCD
)
AND G.EMPLID = 'XXXXXX'
)
SELECT t1.*, t2.*
FROM t1 INNER JOIN t2 ON
t1.empid = t2.empid
Basically you do something like
select blah, blah.. (your second query )
AND G.EMPLID IN ( SELECT DISTINCT C.COMPANY,
C.EMPLID,
C.SSN
FROM PS_PAY_CHECK C
WHERE TO_CHAR(C.CHECK_DT,'YYYY') = '2017'
AND C.COMPANY IN ('001','054','076')
)
So basically I have used your first query in you second query. I removed the DISTINCT, as its not needed.
I hope that makes sense.

Oracle update subquery of records

I need to update a list of record given by a subquery, sniffing around on the web I tried this structure:
UPDATE
(
SELECT
a.COL1
FROM
TABLE1 a,
TABLE2 b
WHERE
a.field1 = b.field1
) update_tbl
SET
update_tbl.COL1 = 'VALUE'
But it returns to me this Oracle error:
-> ORA-01779: Cannot modify a column which maps to a non key-preserved table
My query is the following one:
UPDATE
(
SELECT
imp.*
FROM table1 imp
JOIN table2 sp ON imp.id_p = sp.id_p
JOIN table3 cs ON sp.id_s = cs.id_s
JOIN table4 cb ON cb.id_c = cs.id_c
WHERE
imp.id_b = cb.id_b
AND (
(to_char(imp.p,'yyyymm') < to_char(cb.data_in,'yyyymm')) OR
(cb.data_fi IS NOT NULL AND to_char(imp.p,'yyyymm') > to_char(cb.data_fi,'yyyymm'))
)
and (
(imp.v is not null) or
(imp.v_s is not null and imp.v_s <> 0) or
(imp.imp_co is not null and imp.imp_co <> 0) or
(imp.imp_acc is not null and imp.imp_acc <> 0)
)
) i
SET
i.v = null,
i.v_s = 0,
i.imp_co = 0,
i.imp_acc = 0,
i.ID_S_CONT = 'N',
i.ID_T_COMP = 'P',
i.date_upd = SYSDATE,
i.user_upd = 'SeR'
The subquery return 82 rows (tested now), and I do want to modify only that rows, What am I doing wrong?
I think you are updating to imp table. so you can try MERGE like below
MERGE INTO
IMP A
USING
( SELECT
imp.*
FROM table1 imp
JOIN table2 sp ON imp.id_p = sp.id_p
JOIN table3 cs ON sp.id_s = cs.id_s
JOIN table4 cb ON cb.id_c = cs.id_c
WHERE
imp.id_b = cb.id_b
AND (
(to_char(imp.p,'yyyymm') < to_char(cb.data_in,'yyyymm')) OR
(cb.data_fi IS NOT NULL AND to_char(imp.p,'yyyymm') >
to_char(cb.data_fi,'yyyymm'))
)
and (
(imp.v is not null) or
(imp.v_s is not null and imp.v_s <> 0) or
(imp.imp_co is not null and imp.imp_co <> 0) or
(imp.imp_acc is not null and imp.imp_acc <> 0)
)) B
ON (A.ID =B.ID)
WHEN MATCHED THEN
UPDATE SET
A.v = null,
A.v_s = 0,
A.imp_co = 0,
A.imp_acc = 0,
A.ID_S_CONT = 'N',
A.ID_T_COMP = 'P',
A.date_upd = SYSDATE,
A.user_upd = 'SeR'
Will update the table given by subquery. here A.ID =B.ID use the primary key.

Change IN to EXISTS

I have this 2 query :
Query #1
SELECT A1.clrn_id ,A1.gpgroup ,A1.cl_id
FROM p_dtl A1
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
and A1.clrn_id in (
select clrn_id
from gp_cl_rn run
where run.clrn_id = a1.clrn_id
and run.finalized_ind = :2
)
AND cl_id IN
(
SELECT cl_id
FROM hm_sal
WHERE oprt_id ='004038'
AND runctrl_id = :3
)
Query #2
SELECT B.eid
FROM JBB B
WHERE B.eid IN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = :1
AND estat=:2
)
AND ESTAT = :2
AND acct_type = :3
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
)
How can I change the clrn_id for the 1st query and B.eid for the 2nd query into EXISTS function? And are the bankid, branchid and acct_id also changeable into EXISTS function?
Thanks in advance!
You can change this to a where exists, but you probably want to join instead:
SELECT B.eid
FROM JBB B
JOIN ( SELECT eid, estat, acct_type, acct_id
, max(acct_id) over ( partition by eid ) as max_acct
FROM pbank
) A
ON b.eid = a.eid
JOIN pbranch C
ON a.bankid = c.bankid
AND a.branchid = c.brahchid
WHERE c.sourceid = :1
AND c.estat = :2
AND a.ESTAT = :3
AND a.acct_type = :4
AND a.acct_id = a.max_acct
By using the analytic function max() you remove the need for a sub-select; it's also a lot clearer, I think, to do things in this manner.
And, your newly added query becomes:
SELECT A1.clrn_id, A1.gpgroup, A1.cl_id
FROM p_dtl A1
JOIN gp_cl_rn run
ON A1.clrn_id = run.clrn_id
WHERE A1.PYMT_DT = TO_DATE(:1 ,'YYYY-MM-DD')
AND run.clrn_id = a1.clrn_id
AND run.finalized_ind = :2
I notice that you're explicitly using the to_date() function, which implies that you're storing a date as a string. This is bad practice and likely to cause you trouble in the longer run... avoid it if at all possible.
max(acct_id) over ( partition by eid )
is an analytic function; this does exactly the same as the aggregate function max(), except instead of requiring a GROUP BY, it returns the same result for every row in the result set.
This particular use returns the maximum acct_id for every eid. There's a whole host of analytic functions, but the best thing to do is to try it for yourself. There are also several examples available online.
Using a JOIN is not necessarily quicker than a where exists, it just depends what you're after. As with everything I would recommend trying both and seeing what suits your particular situation more.
Generally, they have different purposes; where exists is designed to stop "calculating" rows when a single row that fulfils the conditions is found. JOIN, does everything. In your case as you want everything there may be little to chose between them but I would always use JOIN; just ensure that your indexes are correct.
I hope, it will help you:
SELECT B.eid
FROM JBB B
where exists
(
SELECT 1
FROM pbank A
WHERE exists
(
SELECT 1
FROM pbranch PB
WHERE PB.sourceid = :1
AND PB.estat=:2
and PB.bankid = A.bankid
AND PB.branchid = A.branchid
)
AND ESTAT = :2
AND acct_type = :3
AND A.eid = B.eid
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.eid = B.eid
AND D.ESTAT = :2
AND D.acct_type = :3)
)
SELECT B.eid
FROM JBB B
JOIN
(
(
SELECT eid
FROM pbank A
WHERE (bankid,branchid) IN
(
SELECT bankid ,branchid
FROM pbranch
WHERE sourceid = 'BNIATB'
AND estat='A'
)
AND ESTAT = 'A'
AND acct_type = 'S'
AND acct_id = (
select max(D.acct_id)
from pbank D
where D.eid = A.eid
AND D.ESTAT = 'A'
AND D.acct_type = 'S')
)
) C on B.eid = c.EID

Resources