where condition to the on clause - sql

I need to modify this sql using a case condition, I need qty to be populated as '1' if serial_number table have the inventory tag available (serial_number.tag_id = inventory.tag_id) else the qty needs to populate from the query results
What would be the best way to do this?
SELECT
* from ( SELECT
inventory.tag_id PalletNumber,
inventory.sku_id sku,
inventory.batch_id batch,
**inventory.qty_on_hand qty,**
inventory.condition_id status,
inventory.user_def_type_1 reasoncode,
serial_number.serial_number serialnumber,
TO_CHAR(inventory.expiry_dstamp, 'YYYY-MM-DD') Expiry_Date,
pre_advice_header.pre_advice_id asn,
pre_advice_header.status asnstatus,
inventory.supplier_id vendor,
TO_CHAR(inventory.receipt_dstamp, 'YYYY-MM-DD') ArrivalDate,
pre_advice_line.host_pre_advice_id PONumber
FROM
inventory
JOIN pre_advice_header ON pre_advice_header.pre_advice_id = inventory.receipt_id
AND pre_advice_header.site_id = inventory.site_id
AND pre_advice_header.client_id = inventory.client_id
AND pre_advice_header.status in ('Complete')
AND pre_advice_header.status is not NULL
LEFT OUTER JOIN pre_advice_line ON pre_advice_line.pre_advice_id = inventory.receipt_id
AND pre_advice_line.sku_id = inventory.sku_id
LEFT JOIN serial_number ON **serial_number.tag_id = inventory.tag_id**
AND serial_number.site_id = inventory.site_id
AND serial_number.client_id = inventory.client_id
AND serial_number.receipt_id = inventory.receipt_id
AND serial_number.sku_id = inventory.sku_id
WHERE
inventory.site_id = 'UK-CBY-04'AND inventory.client_id = 'MLC796'
AND (inventory.condition_id != 'SC1' or inventory.condition_id is null)
AND (inventory.zone_1 <> '80SHP01' or inventory.zone_1 is null)
GROUP BY
inventory.tag_id,
inventory.sku_id,
inventory.batch_id,
inventory.qty_on_hand,
inventory.condition_id,
inventory.user_def_type_1,
serial_number.serial_number,
inventory.expiry_dstamp,
pre_advice_header.pre_advice_id,
pre_advice_header.status,
inventory.supplier_id,
inventory.receipt_dstamp,
pre_advice_line.host_pre_advice_id
ORDER BY
inventory.sku_id DESC,
inventory.tag_id ASC
)

The solution will be as follows using CASE:
CASE WHEN serial_number.serial_number IS NOT NULL THEN 1 ELSE inventory.qty_on_hand END qty

Related

How do I update a column on a table where duplicate records are found

I have this sql script that selects duplicate record . i want to convert it to an update statement where it updates are particular column called STATUS in the table with the string "Duplicated"
Dbms is Oracle
Select * From (
select * from VisaNnsMainTable
Where TRN_TYPE = '500' OR TRN_TYPE = '2500') A
inner join (
select ARN,WAN_NUM, ABS(TRN_AMOUNT) AS AMOUNT
from VisaNnsMainTable
Where TRN_TYPE = '500' OR TRN_TYPE = '2500'
group by ARN, WAN_NUM,ABS(TRN_AMOUNT)
having count(*) > 1
) B on A.ARN = B.ARN
and A.WAN_NUM = B.WAN_NUM
and ABS(A.TRN_AMOUNT) = B.AMOUNT
ORDER BY A.WAN_NUM
Please help me review this I think it does what I want ,but I am not sure if i wrote it well
UPDATE VisaNnsMainTable
SET EXCEPTION = 'Duplicate'
where CONCAT(ARN,WAN_NUM,ABS(TRN_AMOUNT)) in
( select CONCAT(ARN,WAN_NUM,ABS(TRN_AMOUNT))
from VisaNnsMainTable
group by CONCAT(ARN,WAN_NUM,ABS(TRN_AMOUNT))
having count(*) > 1 ) AND (TRN_TYPE = '500' OR TRN_TYPE = '2500')

SQL - Show all values from the first tabel

I want to show all values of a column 'nation.nationen_bez' in the tabel 'nation' using this query:
SELECT DISTINCT nation.nationen_bez,
NVL(SUM (debitor.flimit_deb) OVER (PARTITION BY nation.nationen_bez ORDER BY nation.nationen_bez),0) AS korisceno,
NVL(nation_ext.country_limit,0) - NVL(SUM (debitor.flimit_deb) OVER (PARTITION BY nation.nationen_bez ORDER BY nation.nationen_bez),0) AS se_na_voljo,
NVL(nation_ext.country_limit,0) AS odobren_limit
FROM debitor,
nation,
nation_ext,
firmenstamm,
debitorenstamm
WHERE ( nation.nationen_kode = debitorenstamm.nationen_kode (+)) and
( nation.nationen_id = nation_ext.nationen_id (+)) and
( debitor.debitoren_id = debitorenstamm.debitoren_id ) and
( debitorenstamm.waehrungs_id = firmenstamm.waehrungs_id ) and
( ( debitor.risiko = 1 ) AND
( debitor.factoringart = 'EF' ))
With this query I get only those 'nation.nationen_bez' where exist debitors with debitor.risiko = 1 and
debitor.factoringart = 'EF'. This conditioin is needed for 'NVL(SUM (debitor.flimit_deb) OVER (PARTITION BY nation.nationen_bez ORDER BY nation.nationen_bez),0) AS korisceno', because I want sum only 'flimit_deb' for those debtors that have debitor.risiko = 1 and debitor.factoringart = 'EF' - how can I change this state?
tnx in advance
I have used left join, started with nation
SELECT DISTINCT nation.nationen_bez,
SUM (debitor.flimit_deb) OVER (PARTITION BY nation.nationen_bez ORDER BY nation.nationen_bez) AS korisceno,
nation_ext.country_limit - SUM (debitor.flimit_deb) OVER (PARTITION BY nation.nationen_bez ORDER BY nation.nationen_bez) AS se_na_voljo,
nation_ext.country_limit AS odobren_limit
FROM nation
left join debitorenstamm on nation.nationen_kode = debitorenstamm.nationen_kode
left join debitor on debitorenstamm.debitoren_id = debitor.debitoren_id and debitor.risiko = 1 AND debitor.factoringart = 'EF'
left join nation_ext on nation.nationen_id = nation_ext.nationen_id
left join firmenstamm on debitorenstamm.waehrungs_id = firmenstamm.waehrungs_id

ORA-00920: invalid relational operator with embedded select statement

I'm trying to add an embedded query with in my select statement and its referring a invalid operator
SELECT
hdr.whse, hdr.case_nbr, im.DSP_SKU, batch_nbr, SRL_NBR, PLT_ID, res.DSP_LOCN,
res2.DSP_LOCN prev_locn,
(select locn_brcd from locn_hdr where locn_id = (select locn_id from (select locn_id from at_wh_ghc1.at_case_hdr a where a.case_nbr ) where rownum <= 1)) "3rd",
ACTL_QTY,
DECODE (hdr.stat_code, '00', 'In Transit','01', 'Not Received, Shipment Verified','02', 'In Work Order', '03', 'Work Order Case','10', 'In Inventory, Not Putaway','30', 'Putaway', '45', 'Partially Allocated', '50', 'Allocated', '64', 'Allocated and Pulled', '65', 'Pulled','90', 'In Active Storage','91', 'In Case Pick Storage', '95', 'Consumed','96', 'Case Consumed to Active','97', 'Case Consumed to Case Pick','99', 'Deleted') "Case Status",
count(lock_cnt)as Lock_cnt,
--case when sum(lock_cnt) > 1 then
xmlagg((xmlelement(E,INVN_LOCK_CODE||' ')).extract('//text()') order by INVN_LOCK_CODE)as lock_codes,
hdr.create_date_time
FROM ITEM_MASTER IM
inner join WH_GHC1.CASE_DTL CSD on
csd.sku_id = im.sku_id
inner join WH_GHC1.CASE_HDR hdr on
hdr.case_nbr = csd.case_nbr
left join WH_GHC1.CASE_LOCK CL ON
CL.CASE_NBR = hdr.CASE_NBR
left join WH_GHC1.LOCN_HDR res on
res.LOCN_ID = hdr.LOCN_ID
left join WH_GHC1.LOCN_HDR res2 on
res2.LOCN_ID = hdr.prev_LOCN_ID
left join WH_GHC1.SRL_NBR_TRACK srl on
srl.CASE_NBR = csd.case_nbr
and srl.sku_id = csd.sku_id
and srl.stat_code < 99
where
im.cd_master_id in ('214002','249002')
-- sku/batch ="(im.dsp_sku ='"&C2&"' and csd.batch_nbr = '"&E2&"') or"
-- sku ="(im.dsp_sku ='"&C2&"') or"
and ( (im.dsp_sku ='ONB5STF') ) -- O_o
AND ACTL_QTY > 0
and hdr.stat_code < 90
group by
hdr.whse, hdr.case_nbr, im.DSP_SKU, batch_nbr, SRL_NBR, PLT_ID, res.DSP_LOCN,
res2.DSP_LOCN, ACTL_QTY, hdr.create_date_time, hdr.stat_code
order by
whse, lock_cnt nulls first, dsp_sku;
I added the embedded query to pull an addition location from the location header (select locn_brcd from locn_hdr where locn_id = (select locn_id from (select locn_id from at_wh_ghc1.at_case_hdr a where a.case_nbr ) where rownum <= 1)) "3rd", and then it throws the error code. Can anyone assist with this?
Found 2 issues, first, your 2nd subquery might produce multiple rows, so its safer to use IN instead of equal = operator. Second, limit your subquery to 1.
(select locn_brcd from locn_hdr where locn_id
in (select locn_id from
(select locn_id from at_wh_ghc1.at_case_hdr a
where a.case_nbr ) where rownum <= 1)
and rownum = 1) "3rd",
ACTL_QTY,
I think the issue is here.
(select locn_brcd from locn_hdr where locn_id
in (select locn_id from
(select locn_id from at_wh_ghc1.at_case_hdr a
where a.case_nbr ) where rownum <= 1) -- a.case_nbr is alone in where clause???
-- It must be a.case_nbr = something or you need to remove the entire where clause itself
and rownum = 1) "3rd",
ACTL_QTY,
Cheers!!

Removing duplicates rows in left Joining query

SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
FROM [dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN TargetDate TD ON TD.RecommId = Rec.Reg_ID
WHERE (Det.MissionID = 50 AND [Status].[Status] = 1 AND Rec.Deleted = 0 AND Det.Deleted = 0)
GROUP BY Rec.[Reg_ID],Rec.[Reg_No],Rec.[Case_ID]
,[Status].[Status]
,Det.[Unit_Submission_Date]
,TD.TargetDate
,Det.Deleted
,TD.TargetID
ORDER BY TD.TargetID desc
I have the above query that is supposed to return rows with unique Rec.[Reg_No]. But joined table TargetDate can have duplicate Rec.[Reg_ID] and if thats the case i get duplicate Rec.[Reg_No] rows in my results.
Table TargetDate has a date time column so i want to eliminate the duplicate Rec.[Reg_No] by selecting 1 row with the latest date value from table TargetDate.
How do modify my Join condition or the query where clause to achive the above?
One way is to use a window function such as ROW_NUMBER() that will generate sequential number based on the specified partition. This generated number can then be used to get the latest row.
SELECT Reg_ID, Reg_No, Case_ID, CaseDeleted, [Status], Signature, [Target], TargetID
FROM
(
SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
,RN = ROW_NUMBER() OVER (PARTITION BY Rec.[Reg_No] ORDER BY TD.TargetID DESC)
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN TargetDate TD ON TD.RecommId = Rec.Reg_ID
WHERE (Det.MissionID = 50 AND [Status].[Status] = 1 AND Rec.Deleted = 0 AND Det.Deleted = 0)
) subQuery
WHERE RN = 1
ORDER BY TargetID desc
This query can work correctly if you remove TD.TargetDate from GROUP BY clause and compute what you really need in output - MAX(TD.TargetDate)
But preferable way it to avoid GROUP BY clause at all:
...
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
OUTER APPLY(
SELECT TOP 1 td.TargetDate, td.TargetID
FROM TargetDate TD
WHERE TD.RecommId = Rec.Reg_ID
ORDER BY TD.TargetDate DESC
) td
...
You should first find latest TargetDate for each Reg_ID or RecommId. Then you can use your normal join with TargetDate table just this time with matching both the RecommId and TargetDate.
Try this Query:
SELECT Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,Det.Deleted AS CaseDeleted
,[Status].[Status]
,Det.[Unit_Submission_Date] AS [Signature]
,TD.TargetDate AS [Target]
,TD.TargetID
FROM [BOI].[dbo].[Regestrations] Rec
LEFT JOIN [dbo].[Reg_Details] Det ON Rec.Case_ID = Det.CaseID
LEFT JOIN [dbo].[lkpStatus] [Status] ON Rec.Status_ID = [Status].StatusID
LEFT JOIN (SELECT RecommId, MAX(TargetDate) MaxTargetDate GROUP BY RecommId) TDWithLatestDate ON TDWithLatestDate.RecommId = Rec.Reg_ID
LEFT OUTER JOIN TargetDate ON TD.RecommId = TDWithLatestDate.RecommId AND TD.TargetDate = TDWithLatestDate.MaxTargetDate
WHERE (Det.MissionID = 50
AND [Status].[Status] = 1
AND Rec.Deleted = 0
AND Det.Deleted = 0
)
GROUP BY Rec.[Reg_ID]
,Rec.[Reg_No]
,Rec.[Case_ID]
,[Status].[Status]
,Det.[Unit_Submission_Date]
,TD.TargetDate
,Det.Deleted
,TD.TargetID
ORDER BY TD.TargetID desc
You can improve this query if you want to avoid tie when there more than one record fighting to be latest.

Should a subquery on a join use tables from an outer query in the where clause?

I need to add a subquery to a join, because one payment can have more than one allotment, so I only need to account for the first match (where rownum = 1).
However, I'm not sure if adding pmt from the outer query to the subquery on the allotment join is best.
Should I be doing this differently in the event of performance hits, etc.. ?
SELECT
pmt.payment_uid,
alt.allotment_uid,
FROM
payment pmt
/* HERE: is the reference to pmt.pay_key and pmt.client_id
incorrect in the below subquery? */
INNER JOIN allotment alc ON alt.allotment_uid = (
SELECT
allotment_uid
FROM
allotment
WHERE
pay_key = pmt.pay_key
AND
pay_code = 'xyz'
AND
deleted = 'N'
AND
client_id = pmt.client_id
AND
ROWNUM = 1
)
WHERE
AND
pmt.deleted = 'N'
AND
pmt.date_paid >= TO_DATE('2017-07-01')
AND
pmt.date_paid < TO_DATE('2017-10-01') + 1;
It's difficult to identify the performance issue in your query without seeing an explain plan output. You query does seem to do an additional SELECT on the allotment for every record from the main query.
Here is a version which doesn't use correlated sub query. Obviously I haven't been able to test it. It does a simple join in and then filters all records except one of the allotments. Hope this helps.
WITH v_payment
AS
(
SELECT
pmt.payment_uid,
alt.allotment_uid,
ROW_NUMBER () OVER(PARTITION BY allotment_id) r_num
FROM
payment pmt JOIN allotment alt
ON (pmt.pay_key = alt.pay_key AND
pmt.client_id = alt.client_id)
WHERE pmt.deleted = 'N' AND
pmt.date_paid >= TO_DATE('2017-07-01') AND
pmt.date_paid < TO_DATE('2017-10-01') + 1 AND
alt.pay_code = 'xyz' AND
alt.deleted = 'N'
)
SELECT payment_uid,
allotment_uid
FROM v_payment
WHERE r_num = 1;
Let's know how this performs!
You can phrase the query that way. I would be more likely to do:
SELECT . . .
FROM payment p INNER JOIN
(SELECT a.*,
ROW_NUMBER() OVER (PARTITION BY pay_key, client_id
ORDER BY allotment_uid
) as seqnum
FROM allotment a
WHERE pay_code = 'xyz' AND deleted = 'N'
) a
ON a.pay_key = p.pay_key AND a.client_id = p.client_id AND
seqnum = 1
WHERE p.deleted = 'N' AND
p.date_paid >= DATE '2017-07-01' AND
p.date_paid < (DATE '2017-10-01') + 1;