ORA-00920: invalid relational operator with embedded select statement - sql

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!!

Related

where condition to the on clause

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

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;

Query specific field based on max sequence number

I have a record set where some of the rows are duplicated. In particular, they are duplicated for the last three rows of the record set. Of the entire four rows, the correct result set that I desire would include the first row and the last row. I desire this because for a particular SARAPPD_TERM_CODE_ENTRY, the record needed is the one where the SARAPPD_SEQ_NO value is at its max. So, the first row because for that particular term, the sequence number is maxed at one and the last row because the sequence number is maxed at six. Image and query are below.
select ppd.sarappd_seq_no, ppd.sarappd_term_code_entry, ppd.sarappd_apdc_code,
dap. dap.saradap_term_code_entry,
spri.spriden_id,
t.sgbstdn_astd_code, t.*
from sgbstdn t
left join spriden spri on t.sgbstdn_pidm = spri.spriden_pidm
left join saradap dap on spri.spriden_pidm = dap.saradap_pidm
join sarappd ppd on dap.saradap_pidm = ppd.sarappd_pidm
where t.sgbstdn_astd_code not in ('AS', 'DS', 'WD', 'SU', 'LA')
and t.sgbstdn_stst_code = 'AS'
and spri.spriden_change_ind is null
and spri.spriden_id = '123456789'
and (ppd.sarappd_apdc_code = 25 or ppd.sarappd_apdc_code = 30
or ppd.sarappd_apdc_code =35)
and ppd.sarappd_term_code_entry = dap.saradap_term_code_entry
--where b.sarappd_term_code_entry = ppd.sarappd_term_code_entry)
order by ppd.sarappd_term_code_entry
I believe this is a simple "where this = ( select max() ) type of query but I've been trying some different things and nothing is working. I'm not getting the results I want. So with that said, any help on this would be greatly appreciated. Thanks in advance.
You could use ROW_NUMBER()
;WITH cte
AS
(select
ROW_NUMBER() OVER (PARTITION BY SARAPPD_TERM_CODE_ENTRY ORDER BY SARAPPD_SEQ_NO DESC) AS RN
ppd.sarappd_seq_no,
ppd.sarappd_term_code_entry,
ppd.sarappd_apdc_code,
dap. dap.saradap_term_code_entry,
spri.spriden_id,
t.sgbstdn_astd_code, t.*
from sgbstdn t
left join spriden spri on t.sgbstdn_pidm = spri.spriden_pidm
left join saradap dap on spri.spriden_pidm = dap.saradap_pidm
join sarappd ppd on dap.saradap_pidm = ppd.sarappd_pidm
where t.sgbstdn_astd_code not in ('AS', 'DS', 'WD', 'SU', 'LA')
and t.sgbstdn_stst_code = 'AS'
and spri.spriden_change_ind is null
and spri.spriden_id = '123456789'
and (ppd.sarappd_apdc_code = 25 or ppd.sarappd_apdc_code = 30
or ppd.sarappd_apdc_code =35)
and ppd.sarappd_term_code_entry = dap.saradap_term_code_entry
order by ppd.sarappd_term_code_entry) a
SELECT *
FROM cte WHERE rn = 1

sum NULL or converting NULL to 0 to sum sql db2.iseries

I am a newbee at SQL and am currently trying to query a DB2.iSeries database, and I am stuck.
This is my code:
SELECT IPROD, IDESC, IMRP, NONAV
FROM
(SELECT IPROD, IDESC, IMRP FROM IIM WHERE IBUYC IN (<pln.value>) AND IMRP = 'N') AS IM
INNER JOIN
(SELECT I01PROD FROM INV01P
WHERE I01SUPS = '0'
AND I01SUPP = '0')
AS L1 ON IM.IPROD = L1.I01PROD
LEFT OUTER JOIN
(SELECT WPROD, SUM(WOPB-WISS+WADJ+WRCT) AS NONAV FROM IWI
WHERE LEFT(WWHS,1) = '9'
GROUP BY WPROD) AS L2 ON IM.IPROD = L2.WPROD
GROUP BY IPROD, IDESC, IMRP, NONAV
HAVING SUM(NONAV) = 0
ORDER BY IPROD
FETCH FIRST 10000 ROWS ONLY
This is the code that I have which works fine when querying: HAVING SUM(NONAV) = 0, but the problem I have is there are products which have NULL value, which I also need to pull.
I have tried IFNULL, CASE WHEN at different points with the query, but it fails.
I know how to have the field output view with 0, but when it comes to having sum, it fails to pull these products.
Could someone please help me to pull NULL and 0 values once the field is summed.
Thanks
SELECT IPROD, IDESC, IMRP, NONAV
FROM
(SELECT IPROD, IDESC, IMRP FROM IIM WHERE IBUYC IN (<pln.value>) AND IMRP = 'N') AS IM
INNER JOIN
(SELECT I01PROD FROM INV01P
WHERE I01SUPS = '0'
AND I01SUPP = '0')
AS L1 ON IM.IPROD = L1.I01PROD
LEFT OUTER JOIN
(SELECT WPROD, SUM(WOPB-WISS+WADJ+WRCT) AS NONAV FROM IWI
WHERE LEFT(WWHS,1) = '9'
GROUP BY WPROD) AS L2 ON IM.IPROD = L2.WPROD
GROUP BY IPROD, IDESC, IMRP, NONAV
HAVING SUM(COALESCE(NONAV,0)) = 0
ORDER BY IPROD
FETCH FIRST 10000 ROWS ONLY

Major issues with a query

I have a query
SELECT
ZEML.ICC_CODE AS ICC_CODE
,SUM(CS.TOT_HOURS) AS TOT_HOURS
,SUM(CS.NUM_INCIDENT_ALL) AS NUM_INCIDENTS
,(VALUE(FLOAT(SUM(CS.NUM_INCIDENT_ALL)) * 200000 / SUM(TOT_HOURS)
,0)) AS INC_RATE
FROM TR.CLAIMS_SUMM CS
INNER JOIN TR.LOCATION_MASTER LM
ON LM.LOCATION = CS.LOCATION
AND CS.LOCATION < '900'
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE = 'District'
LEFT JOIN TR.LOCATION_ASSIGNMENTS TERRITORY
ON TERRITORY.LOCATION = LM.LOCATION
AND TERRITORY.ASSIGNMENT_TYPE = 'Territory'
LEFT JOIN TR.EMPL_CLAIMS ZEML
ON CS.LOCATION = ZEML.LOCATION
AND ZEML.TYPE = 'WC'
AND ZEML.STATUS <> 'V'
AND ZEML.CLAIM_ACTION NOT IN ('D','F','I','H')
WHERE CS.DW_DATE BETWEEN '01/01/2014'
AND '05/31/2014'
AND (MONTH(ZEML.DATE_OF_INCIDENT) = MONTH(CS.DW_DATE)
AND YEAR(ZEML.DATE_OF_INCIDENT) = YEAR(CS.DW_DATE))
GROUP BY ZEML.ICC_CODE
UNION
SELECT
'OTHER' AS ICC_CODE
, 0 AS TOT_HOURS
, 0 AS NUM_INCIDENTS
, 0 AS INC_RATE
FROM SYSIBM.SYSDUMMY1
WHERE 1 = 1
ORDER BY 1
in my union where I made an other I want to select everything else from the tr.empl_claims table and store it in the other from the union because this is what I have many other ICC codes without incidents on them and I am doing calculations on our incident rate and hourse based off of all the data but my query right now is only selecting the ones that currently is having incidents which is throwing off my calculations.
From your use of FROM SYSIBM.SYSDUMMY1 I believe you are using DB2 database. If yes, you can use CTE (common table expression) to achieve the desired result like
WITH cte1 AS
(
SELECT
ZEML.ICC_CODE AS ICC_CODE
,SUM(CS.TOT_HOURS) AS TOT_HOURS
,SUM(CS.NUM_INCIDENT_ALL) AS NUM_INCIDENTS
,(VALUE(FLOAT(SUM(CS.NUM_INCIDENT_ALL)) * 200000 / SUM(TOT_HOURS)
,0)) AS INC_RATE
FROM TR.CLAIMS_SUMM CS
... <rest of the code> ...
)
select * from cte1
UNION ALL
SELECT
ICC_CODE
, 0 AS TOT_HOURS
, 0 AS NUM_INCIDENTS
, 0 AS INC_RATE
FROM TR.EMPL_CLAIMS
WHERE ICC_CODE NOT IN
(
SELECT distinct ICC_CODE
FROM cte1
)
ORDER BY 1
SideNote: You are joining the same table LOCATION_ASSIGNMENTS twice (as below) which is not needed.
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE = 'District'
LEFT JOIN TR.LOCATION_ASSIGNMENTS TERRITORY
ON TERRITORY.LOCATION = LM.LOCATION
AND TERRITORY.ASSIGNMENT_TYPE = 'Territory'
This can be transformed to below using a IN operator
LEFT JOIN TR.LOCATION_ASSIGNMENTS DISTRICT
ON DISTRICT.LOCATION = LM.LOCATION
AND DISTRICT.ASSIGNMENT_TYPE IN ('District', 'Territory')
See more about Common Table Expression in DB2 Here.
Hope this helps.