Oracle SQL update statement how to update two rows at a time - sql

I tried to update two rows in a table.
If I used:
update ERNTESTUPDATE a
set (date_loaded, acad_career) = (select distinct b.date_loaded, b.acad_career
from PS_STDNT_ENRL b
where rownum=1)
where to_char(date_created) = to_char(trunc(sysdate))
;
I got 2 rows updated as
11/29/18 UGRD
11/29/18 UGRD
If I used:
update ERNTESTUPDATE a
set (date_loaded, acad_career) = (select distinct b.date_loaded, b.acad_career
from PS_STDNT_ENRL b
where a.date_loaded = b.date_loaded )
where to_char(date_created) = to_char(trunc(sysdate))
;
I got an error
single-row subquery returns more than one row
How to get a result as below:
11/29/18 UGRD
11/29/18 GRAD
Thank you,
Kate

The subquery needs to return a SINGLE row. That works well when you include the condition rownum=1 in the first one:
select distinct b.date_loaded, b.acad_career
from PS_STDNT_ENRL b
where rownum=1 -- this filter makes sure only one row is returned
If you remove that condition, then the subquery will return multiple rows, and that makes the whole UPDATE fail.

Related

Update Query that Lists Rows Not Updated

I have a 12 million row SQL Server table that when I run the following query it shows approximately 11.6 million rows updated:
UPDATE [HCRIS]
SET [HCRIS].[ST_ABB] = dbo.[PRVDR_CHANGE].[state_abbreviation]
FROM [HCRIS]
INNER JOIN dbo.[PRVDR_CHANGE]
ON [HCRIS].[PRVDR_NUM] = dbo.[PRVDR_CHANGE].[PRVDR_NUM]
WHERE [HCRIS].[PRVDR_NUM] = dbo.[PRVDR_CHANGE].[PRVDR_NUM];
I have checked for nulls and non-numeric values in a numeric column but would love to pinpoint those rows that were not updated. My intent is to update all rows.
Thank you.
Use EXCEPT to find rows that won't get updated - where you select all rows in the first query and rows you would have updated in the second.
SELECT H.*
FROM [HCRIS] H
EXCEPT
SELECT H.*
FROM dbo.[HCRIS] H
INNER JOIN dbo.[PRVDR_CHANGE] C
ON H.[PRVDR_NUM] = C.[PRVDR_NUM]
WHERE H.[PRVDR_NUM] = C.[PRVDR_NUM];

Oracle SQL Update statement with value generated in subquery

I am trying to write an update statement to insert a value that's calculated in a subquery, and having limited success.
The statement I've tried so far is:
update intuit.men_doc doc1
set doc1.doc_udf5 = (select
substr(doc.doc_dtyc, instr(doc.doc_dtyc, 'GAPP-', 2)+5 )||'_'||row_number() over(partition by
doc.doc_dtyc order by doc.doc_cret) docDeleteId
from
intuit.men_doc doc
where
doc.doc_dtyc != 'DM-GAPP-SFUL'
and doc.doc_dtyc like 'DM-GAPP%'
and doc.doc_cred >= '01/Oct/2017' and doc.doc_cred < '01/Oct/2018'
and doc1.doc_code = doc.doc_code
)
Which gives mes the following error message
ERROR: Error 1427 was encountered whilst running the SQL command. (-3)
Error -3 running SQL : ORA-01427: single-row subquery returns more than one row
I don't have much experience with UPDATE statements, so any advice on how I can rewrite this so that I can update a few thousand records at once would be appreciated.
EDIT: Adding example data
Example data:
MEN_DOC
DOC_CODE DOC_DTYC DOC_UDF5 DOC_CRED
123456A CV 08/Nov/2017
456789B CV 11/Jan/2018
789123C CV 15/Feb/2018
123987B TRAN 01/Dec/2017
How I want the data to look once the script is run
MEN_DOC
DOC_CODE DOC_DTYC DOC_UDF5 DOC_CRED
123456A CV CV_1 08/Nov/2017
456789B CV CV_2 11/Jan/2018
789123C CV CV_3 15/Feb/2018
123987B TRAN TRAN_1 01/Dec/2017
Thanks
You are using row_number(), which suggests that you expect the subquery to return more than one row. The inequality on doc_code supports this interpretation.
Just change the row_number() to count(*), so you have an aggregation which will always return one row and get the sequential count you want:
update intuit.men_doc doc1
set doc1.doc_udf5 = (select substr(doc.doc_dtyc, instr(doc.doc_dtyc, 'GAPP-', 2)+5 ) ||'_'|| count(*) docDeleteId
from intuit.men_doc doc
where doc.doc_dtyc <> 'DM-GAPP-SFUL' and
doc.doc_dtyc like 'DM-GAPP%' and
doc.doc_cred >= date '2017-10-01' and
doc.doc_cred < date '2018-10-01' and
doc1.doc_code = doc.doc_code
);
You can use your select as source table in merge, like here:
merge into men_doc tgt
using (select doc_code,
doc_dtyc||'_'||row_number() over (partition by doc_dtyc order by doc_cred) as calc
from men_doc) src
on (tgt.doc_code = src.doc_code)
when matched then update set tgt.doc_udf5 = src.calc;
dbfiddle
I assumed that doc_code is unique.

Using max-function in subquery relating to main query

I have the following problem:
I have two tables TAB_1 and TAB_2.
In TAB_1 I would like to fill in column FEAT_A1 with a matching value in TAB_2. Hence, I join both tables on their common feature FEAT_B.
Unfortunately, per FEAT_B2-ID in TAB_2 there are multiple records. I would like to use the matching record, for which FEAT_D2 is maximal.
I can perform this operation with the code shown below. Unfortunately, the code is super slow since, per match, I have to perform one order- and one fetch-operation.
Can you think of a more efficient way to program this?
To clarify things, here is an example of TAB_2 records:
FEAT_A2 FEAT_B2 FEAT_C2 FEAT_D2
"A" 42 "SOMETHING" 7
"B" 42 "SOMETHING" 11
"D" 42 "SOMETHING" 1
"A" 42 "SOMETHING" 3
In TAB_1, for FEAT_B1 = 42, I would like to set FEAT_A1 = "B".
UPDATE TAB_1
SET TAB_1.FEAT_A1 = (
SELECT FEAT_A2 FROM TAB_2
WHERE TAB1.FEAT_B1 = TAB2.FEAT_B2
AND TAB2.FEAT_C2 = 'SOMETHING'
ORDER BY TAB2.FEAT_D2 DESC
FETCH FIRST 1 ROW ONLY);
For this query:
UPDATE TAB_1
SET TAB_1.FEAT_A1 =
(SELECT FEAT_A2
FROM TAB_2
WHERE TAB1.FEAT_B1 = TAB2.FEAT_B2 AND
TAB2.FEAT_C2 = 'SOMETHING'
ORDER BY TAB2.FEAT_D2 DESC
FETCH FIRST 1 ROW ONLY
);
You want an index on tab_2(FEAT_B1, FEAT_C2, FEAT_D2 DESC). This should be a notable performance improvement.
That said, you are going to be updating all rows in TAB_1. If that table is no small, then there will be a lot of overhead just for doing the updates.
I would suggest using merge for it.
MERGE INTO TAB_1 T1
USING (SELECT FEAT_A2, FEAT_B2,
ROW_NUMBER() OVER (PARTITION BY FEAT_B2
ORDER BY FEAT_D2 DESC NULLS LAST) AS RN
FROM TAB_2) T2
ON (T1.FEAT_B1 = T2.FEAT_B2 AND T2.RN = 1)
WHEN MATCHED THEN
UPDATE SET T1.FEAT_A1 = T2.FEAT_A2
Cheers!!

newbie oracle update statement error

oracle query:
UPDATE AIRMODEL_NETWORK_SUMMARY
SET CASES_PRODUCED = (SELECT DISTINCT PRDCTN_RUN_ACTL_CASE_QTY
FROM AIRMODEL_NETWORK_SUMMARY, HISTORY_PRODUCTION, PERIOD_TO_PROCESS
WHERE AIRMODEL_NETWORK_SUMMARY.FSCL_WK_IN_YR_NUM = HISTORY_PRODUCTION.FSCL_WK_IN_YR_NUM
AND AIRMODEL_NETWORK_SUMMARY.FSCL_YR_NUM = HISTORY_PRODUCTION.FSCL_YR_NUM
AND AIRMODEL_NETWORK_SUMMARY.LOC_ID = HISTORY_PRODUCTION.LOC_ID
AND HISTORY_PRODUCTION.FSCL_WK_IN_YR_NUM = PERIOD_TO_PROCESS.FSCL_WK_IN_YR_NUM
AND HISTORY_PRODUCTION.FSCL_YR_NUM = PERIOD_TO_PROCESS.FSCL_YR_NUM);
is returning the following error:
ORA-01427: single-row subquery returns more than one row
Another attempt at correction:
MERGE INTO AIRMODEL_NETWORK_SUMMARY AIRMODEL_NETWORK_SUMMARY1
USING (SELECT DISTINCT PRDCTN_RUN_ACTL_CASE_QTY,
AIRMODEL_NETWORK_SUMMARY2.rowid AS r
FROM AIRMODEL_NETWORK_SUMMARY AIRMODEL_NETWORK_SUMMARY2
INNER JOIN HISTORY_PRODUCTION
ON AIRMODEL_NETWORK_SUMMARY2.FSCL_WK_IN_YR_NUM = HISTORY_PRODUCTION.FSCL_WK_IN_YR_NUM
AND AIRMODEL_NETWORK_SUMMARY2.FSCL_YR_NUM = HISTORY_PRODUCTION.FSCL_YR_NUM
AND AIRMODEL_NETWORK_SUMMARY2.LOC_ID = HISTORY_PRODUCTION.LOC_ID
INNER JOIN PERIOD_TO_PROCESS
ON HISTORY_PRODUCTION.FSCL_WK_IN_YR_NUM = PERIOD_TO_PROCESS.FSCL_WK_IN_YR_NUM
AND HISTORY_PRODUCTION.FSCL_YR_NUM = PERIOD_TO_PROCESS.FSCL_YR_NUM)
ON (AIRMODEL_NETWORK_SUMMARY1.rowid = r)
WHEN MATCHED THEN UPDATE
SET CASES_PRODUCED = PRDCTN_RUN_ACTL_CASE_QTY;
returns the following error:
ORA-30926: unable to get a stable set of rows in the source tables
I am a noob and need help :(
thank you.
You can assign only a single, scalar value to CASES_PRODUCED. So your subquery needs to produce only a single, scalar value.
You need to find why your subquery returns more than one row.
SELECT DISTINCT ... will select unique rows, not the same as ONE ROW.
Do you need the sum total of all the PRDCTN_RUN_ACTL_CASE_QTY in the rows?
Or the average?
Or the MAX number?
Or the first row?
Use an aggregate function if so:
Total
UPDATE AIRMODEL_NETWORK_SUMMARY
SET CASES_PRODUCED = (SELECT SUM(PRDCTN_RUN_ACTL_CASE_QTY) ...
Max
UPDATE AIRMODEL_NETWORK_SUMMARY
SET CASES_PRODUCED = (SELECT MAX(PRDCTN_RUN_ACTL_CASE_QTY) ...
Average
UPDATE AIRMODEL_NETWORK_SUMMARY
SET CASES_PRODUCED = (SELECT AVG(PRDCTN_RUN_ACTL_CASE_QTY) ...
First row
UPDATE AIRMODEL_NETWORK_SUMMARY
SET CASES_PRODUCED = (SELECT PRDCTN_RUN_ACTL_CASE_QTY ...
FROM ...
WHERE ROWNUM = 1)
It is critical, especially when learning, and struggling with syntax, that you clearly understand
What you need from the query
What your query is returning
Just trying a bunch of alternatives until you get success is a sure fire way to create erroneous data that seems to work.
My suggestion is to first copy the subquery SELECT to a different window and run it, view and understand the results. It should be clear that it is a multi-row result. Work with the subquery until it is returning a correct, single result, then plug it back into the larger update.

MAX Subquery in SQL Anywhere Returning Error

In sqlanywhere 12 I wrote the following query which returns two rows of data:
SELECT "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM "eDatabase"."OrderingInfo"
JOIN "eDatabase"."Vendor"
ON "eDatabase"."OrderingInfo"."ORD_VEN_FK" = "eDatabase"."Vendor"."VEN_PK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
Which returns:
'**United Natural Foods IN','2018-02-07 15:05:15.513'
'Flora ','2018-02-07 14:40:07.491'
I would like to only return the row with the maximum timestamp in the column "ORD_Timestamp". After simply trying to select by MAX("eDatabase"."OrderingInfo"."ORD_Timestamp") I found a number of posts describing how that method doesn't work and to use a subquery to obtain the results.
I'm having difficulty creating the subquery in a way that works and with the following query I'm getting a syntax error on my last "ON":
SELECT "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM ( "eDatabase"."OrderingInfo"
JOIN
"eDatabase"."OrderingInfo"
ON "eDatabase"."Vendor"."VEN_PK" = "eDatabase"."OrderingInfo"."ORD_VEN_FK" )
INNER JOIN
(SELECT "eDatabase"."Vendor"."VEN_CompanyName", MAX("eDatabase"."OrderingInfo"."ORD_Timestamp")
FROM "eDatabase"."OrderingInfo")
ON "eDatabase"."Vendor"."VEN_PK" = "eDatabase"."OrderingInfo"."ORD_VEN_FK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
Does anyone know how I can adjust this to make the query correctly select only the max ORD_Timestamp row?
try this:
SELECT TOP 1 "eDatabase"."Vendor"."VEN_CompanyName", "eDatabase"."OrderingInfo"."ORD_Timestamp"
FROM "eDatabase"."OrderingInfo"
JOIN "eDatabase"."Vendor"
ON "eDatabase"."OrderingInfo"."ORD_VEN_FK" = "eDatabase"."Vendor"."VEN_PK"
WHERE ORD_INV_FK='7853' AND ORD_DefaultSupplier = 1
order by "ORD_Timestamp" desc
this orders them biggest on to and say only hsow the top row