Not able to update columns of a table by bind parameters using sql developer - sql

The following select statement returns one row:
SELECT *
FROM CM_APOLLO_DET
WHERE
CM_APOLLO_DET.DETAIL_ID = TRIM(:detailId) AND
CM_APOLLO_DET.HEADER_ID IN (SELECT HEADER_ID FROM CM_APOLLO_HDR
WHERE TRIM(FILE_NAME) = TRIM(:fileName));
Values of bind parameters are as follows:
detailId: 775686609762
filename:sample3.txt
but when I run following update statement, it updates zero rows.
UPDATE CM_APOLLO_DET
SET CM_APOLLO_DET.DIVISION = :div
WHERE
CM_APOLLO_DET.DETAIL_ID = TRIM(:detailId) AND
CM_APOLLO_DET.HEADER_ID IN (SELECT HEADER_ID FROM CM_APOLLO_HDR
WHERE TRIM(FILE_NAME) = TRIM(:fileName));
div=2030
detailId: 775686609762
filename:sample3.txt
This update where condition is same as above select statement.

You can try below using exists
update CM_APOLLO_DET set CM_APOLLO_DET.DIVISION=:div
where CM_APOLLO_DET.DETAIL_ID=trim(:detailId) and
exists (SELECT 1 from
CM_APOLLO_HDR where CM_APOLLO_DET.HEADER_ID=CM_APOLLO_HDR.HEADER_ID
and trim(FILE_NAME)=trim(:fileName)
);

Related

How to store data from a SELECT statement and use that data to loop with an UPDATE statement

I am using PLSQL and I want to store the query results form SELECT statement in an array and then I want to loop using the elements from that array to UPDATE all the rows. The problem with the code below is that it returns a single-row. Sub-query returns more than one row because he is trying to set more than one variable in a row. Can you help me in this situation?
This is my code:
CREATE OR REPLACE PROCEDURE looping IS
BEGIN
FOR rec IN (SELECT IID FROM DATMCCN0)
LOOP
UPDATE DATMCCN0
SET E_NOME = (SELECT I_NOME FROM DAT_CCNCONFIG0 INNER JOIN DATMCCN0 ON DAT_CCNCONFIG0.I_NOME = DATMCCN0.CAPLIC where DATMCCN0.IID = rec.IID)
where IID = rec.IID;
END LOOP;
END;
EXECUTE looping;
You do not need a loop and can do it all in one MERGE statement (assuming your correlated query returns a single row for each IID):
CREATE OR REPLACE PROCEDURE looping
IS
BEGIN
MERGE INTO DATMCCN0 dst
USING (
SELECT b.IID,
I_NOME
FROM DAT_CCNCONFIG0 a
INNER JOIN DATMCCN0 b
ON a.I_NOME = b.CAPLIC
) src
ON ( src.IID = dst.IID)
WHEN MATCHED THEN
UPDATE SET E_NOME = src.I_NOME;
END;
If it does not then you will need to get only a single row, something like this:
CREATE OR REPLACE PROCEDURE looping
IS
BEGIN
MERGE INTO DATMCCN0 dst
USING (
SELECT b.IID,
MAX( I_NOME ) AS I_NOME
FROM DAT_CCNCONFIG0 a
INNER JOIN DATMCCN0 b
ON a.I_NOME = b.CAPLIC
GROUP BY b.IID
) src
ON ( src.IID = dst.IID)
WHEN MATCHED THEN
UPDATE SET E_NOME = src.I_NOME;
END;
One literal answer for your question "How to store data from a SELECT statement and use that data [to loop] with an UPDATE statement" would be a statement like this:
UPDATE
(SELECT src.E_NOME, dst.I_NOME
FROM DAT_CCNCONFIG0
JOIN DATMCCN0 src ON DAT_CCNCONFIG0.I_NOME = scr.CAPLIC
JOIN DATMCCN0 dst ON src.IID = dst.IID)
SET E_NOME = I_NOME;
However, it does not solve your problem that a single-row subquery returns more than one. Have a look at MT0's answer for that.

How to update all of the values of a table using merge into statement

How to update all the values from source table to destination table using merge into statement?
What I am trying to do is something like:
merge into src_table
using (select * from dest) dest_table
on (<some_condition>)
when matched then update set src_table.* = dest_table.*
where <condition>
I didn't find anything related to this on Google. I know one can achieve this using execute immediate style statement but I am looking for a better way.
you can do it with pl/sql
for src in ( select * from B ) loop
update A set ROW = src where A.id = src.id;
end loop;
or you can use alter table;
alter table your_table
rename to
your_new_table;

How to update two different tables using a single UPDATE statement

I am trying to update two tables with a single statement like this
db2 update catentry, catentdesc
set catentry.buyable=0,
catentdesc.published=0
where catentry.catentry_id=catentdesc.catentry_id
and catentry.partnumber='some value'
but getting an error
How can I accomplish this?
Set DB2 CLP to autocommit OFF and use ; command terminator:
db2 +c -t
update catentry set buyable=0 where partnumber='some value';
update catentdesc set published=0 where catentry_id IN
(SELECT catentry_id FROM catentry where partnumber='some value');
commit;
Not sure why you want to do this in a single statement, but recent versions of DB2 for LUW (and, with some restrictions, DB2 for z/OS) support what is called data change table references that allow tricks like
WITH t1 (catentry_id) AS (
SELECT catentry_id FROM FINAL TABLE (
UPDATE catentry SET buyable = 0 WHERE partnumber = 'some value'
)
), t2 (catentry_id) AS (
SELECT catentry_id FROM FINAL TABLE (
UPDATE catentdesc SET published = 0 WHERE catentry_id = (
SELECT catentry_id FROM t1
)
)
) SELECT 1 FROM sysibm.sysdummy1
Note that the actual statement must be a SELECT from something, and UPDATE statements are also wrapped in their own SELECTs, but this is executed as a single statement.

Update Trigger Affecting Too Many Rows

I wrote the following trigger:
begin
update NFL.TeamStatistics
set Passing_Yards = (select sum(Quarterbacks.Yards)
from NFL.Quarterbacks
where Quarterbacks.Team = inserted.Team)
from NFL.Quarterbacks
inner join inserted on Quarterbacks.Team = inserted.Team;
Whenever someone updates the passing yards in the table about quarterbacks, it should automatically set NFL.TeamStatistics.Passing_Yards to the sum of each team's passing yards.
I used the following update statement to test it:
update NFL.Quarterbacks
set Quarterbacks.Yards = 4000
where Team = 'PIT';
However, in the table NFL.TeamStatistics it set the passingyards for all teams to 4000 instead of just for PIT. What is the matter?
You need to add a where clause and column in NFL.TeamStatistics that you want to compare to
e.g:
begin
update NFL.TeamStatistics
set Passing_Yards = (select sum(Quarterbacks.Yards)
from NFL.Quarterbacks
where Quarterbacks.Team = inserted.Team)
from NFL.Quarterbacks
inner join inserted on Quarterbacks.Team = inserted.Team
where Team = Quarterbacks.Team;
Assuming you were comparing to Quaterbacks.Team
You should use where clause in your update statement in order to filter data you are going to update.

T-SQL - need to run update if only one record returned by query

I need to update a record IFF there is only one record matching my search criteria. Here's what I have, but it's crude:
DECLARE #TestCount INT;
SELECT #TestCount = COUNT(*)
FROM TestRecords tr
WHERE
tr.UnitSerial = #UnitSerial
AND
tr.PassFailStatus = 1;
IF (#TestCount = 1)
UPDATE
TestRecords
SET
Invalid = 1
WHERE
TestRecordID =
(SELECT TestRecordID
FROM TestRecords tr
WHERE
tr.UnitSerial = #UnitSerial
AND
tr.PassFailStatus = 1);
Of course this is example code - there are more restrictions and tables joins, etc in the SELECT statement, and it's all wrapped by a transaction, but this is the gist of the stored proc logic.
I'm thinking there has to be a better way but I don't know what that is. Any suggestions?
Thanks, Dave
You could do it in one query as:
with toupdate as (
select tr.*,
count(*) over () as cnt
from TestRecords tr
where tr.UnitSerial = #UnitSerial AND tr.PassFailStatus = 1
)
update toupdate
set Invalid = 1
where cnt = 1
This assumes you are using SQL 2005 or greater.
I think your code will run without problems!
Use ##ROWCOUNT variable to determine how many records was affected by a SELECTE, UPDATE, INSERT statement: but in your case you have just set your #TestCount variable with the same result!
It's not far off what I would do, which is simply:
IF (SELECT COUNT(*) FROM x WHERE y = z) = 1
BEGIN
--statements
END
Of course, you could replace the condition with anything, e.g. a UDF with more complex dynamic conditions.