Optimizing sql update syntax rather than the Server - sql

There are two tables, one is getting updated based on second table. The SQL is working but it is taking too much time because of number of records, i think. See this fiddle. The actual master table contains 1,500,000 and child contains 700,000 records and the following sql kept executing for 4 hours, hence terminated.
UPDATE master m SET m.amnt = (SELECT amnt FROM child c WHERE c.seqn = m.seqn)
WHERE m.seqn IN (SELECT seqn FROM child);
The execution plan of this sql is (Red one is master, other is child)
seqn is the primary key. No doubt it all depends upon server's performance and stats of indices. However, It bothers me that master is not being accessed by the index and child is being read twice. It is possible that the sql is optimized but oracle decided to go in this way, however i tried to optimize the sql as
UPDATE (
SELECT m.seqn m_seqn,c.seqn c_seqn, c.amnt c_amnt, m.amnt m_amnt
FROM master m INNER JOIN child c ON m.seqn = c.seqn)
SET m_amnt = c_amnt
which resulted in following error
ORA-01779: cannot modify a column which maps to a non key-preserved
table : UPDATE ( SELECT m.seqn m_seqn,c.seqn c_seqn, c.amnt c_amnt, m.amnt m_amnt
FROM master m INNER JOIN child c ON m.seqn = c.seqn) SET m_amnt = c_amnt
Is there any way i can optimize the SQL other than updating stats and tuning up the server?
EDIT The solution by #Sebas will not work if the column to be JOINED ON is not PK

check this one out:
UPDATE
(
SELECT m.amnt AS tochange, c.amnt AS newvalue
FROM child c
JOIN master m ON c.seqn = m.seqn
) t
SET t.tochange = t.newvalue;
SELECT * FROM master;
fiddle: http://www.sqlfiddle.com/#!4/c6b73/2
you just missed the PK in the fiddle.

Related

Oracle Sql tuning with index

I have a table T with some 500000 records. That table is a hierarchical table.
My goal is to update the table by self joining the same table based on some condition for parent - child relationship
The update query is taking really long because the number of rows is really high. I have created an unique index on the column which helps identifying the rows to update (meanign x and Y). After creating the index the cost has reduced but still the query is performing a lot slower.
This my query format
update T
set a1, b1
= (select T.parent.a1, T.parent.b1
from T T.paremt, T T.child
where T.parent.id = T.child.Parent_id
and T.X = T.child.X
and T.Y = T.child.Y
after creating the index the execution plan shows that it is doing an index scan for CRS.PARENT but going for a full table scan for for CRS.CHILD and also during update as a result the query is taking for ever to complete.
Please suggest any tips or recommendations to solve this problem
You are updating all 500,000 rows, so an index is a bad idea. 500,000 index lookups will take much longer than it needs to.
You would be better served using a MERGE statement.
It is hard to tell exactly what your table structure is, but it would look something like this, assuming X and Y are the primary key columns in T (...could be wrong about that):
MERGE INTO T
USING ( SELECT TC.X,
TC.Y,
TP.A1,
TP.A2
FROM T TC
INNER JOIN T TP ON TP.ID = TC.PARENT_ID ) U
ON ( T.X = U.X AND T.Y = U.Y )
WHEN MATCHED THEN UPDATE SET T.A1 = U.A1,
T.A2 = U.A2;

Cannot update a table using a simple inner join

I have 2 tables in access 2007.
See attached picture to see the structure of the tables and the expected result.
I am trying to update the quantity field (ITQTY) in TABLE_BLNC by summarizing all the quantity field (LOCQTY) from TABLE_DTL for same items (LOITNBR=ITNBR).
In TABLE_BLNC, the item is unique while in TABLE_DTL, the item can be in multiple records.
My query is:
UPDATE TABLE_BLNC INNER JOIN
(
SELECT LOITNBR, Sum(LOCQTY) AS SumOfLOCQTY FROM TABLE_DTL GROUP BY LOITNBR) AS DTL
ON TABLE_BLNC.ITNBR=DTL.LOITNBR SET TABLE_BLNC.ITQTY = DTL.SumOfLOCQTY;
I am getting the error:
Operation must use an updateable query.
Domain Aggregate functions can be useful when Access complains that an UPDATE is not updateable. In this case, use DSum() ...
UPDATE TABLE_BLNC
SET ITQTY =
DSum("LOCQTY", "TABLE_DTL", "LOITNBR='" & ITNBR & "'");
Index TABLE_DTL.LOITNBR for optimum performance.
One of the great annoyances of Access SQL is its inability to update a table from an non-updatable source. Non-updatable sources include read-only links to ODBC tables, and GROUP BY (summary) queries.
What I always do is:
Copy the structure of TABLE_BLNK to a temp table: TABLE_BLNK_temp.
In your code, first delete the temp:
DELETE * FROM TABLE_BLNK_temp;
Insert the result of your summary query into temp:
INSERT INTO TABLE_BLNK_temp (ITNBR, ITQTY)
SELECT LOITNBR, Sum(LOCQTY) AS SumOfLOCQTY
FROM TABLE_DTL GROUP BY LOITNBR;
Update TABLE_BLNK from TABLE_BLNK_temp:
UPDATE TABLE_BLNC INNER JOIN TABLE_BLNK_temp AS t
ON TABLE_BLNC.ITNBR = t.ITNBR
SET TABLE_BLNC.ITQTY = t.ITQTY;
While it is an extra step or two, this approach:
Always works
Is more performant than Domain Aggregate functions for larger datasets

SQL Update using value from join table

I tried using this sql to update a new column in a table from a value in table that already exists.
update "PROMOTION" t1
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc
inner join "PROMOTION" on "PROMOTION"."ID" = poc."PROMOTION_ID"
What happened is that the first value of the join got replicated in all the subsequent entries. about a both tables. The original table has unique values all the values in the updated column are the same.
Eventually I used this SQL instead.
update "PROMOTION" t1
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc
where
t1."ID" = poc."PROMOTION_ID"
This update works and duplicates all the data, 1000 unique elements in the original table, 1000 unique elements in the updated table.
Is this a bug, or is this the expected result?
SQL is behaving correctly. Your original query is:
update "PROMOTION" t1
--------^
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc inner join
"PROMOTION"
-----------^
on "PROMOTION"."ID" = poc."PROMOTION_ID"
Note that the table PROMOTION is mentioned twice. Not good. So, the join takes place, producing lots of rows. Then there is no correlation to the t1 version of the table.
You don't mention the database you are using. In SQL Server, you would just do:
update p
set "OFFER_CHAIN_ID" = poc."OFFER_CHAIN_ID"
from "PROMOTION_OFFER_CHAIN" poc inner join
"PROMOTION" p
on p."ID" = poc."PROMOTION_ID";
Note the alias is used after the update (or table name with if there is no alias). Now the table is mentioned only once, so the update should behave as desired.

Oracle updating table based on a join

I have two tables
table 1 : rm_example(customer, weekno, salenum, card_type,...., imputed)
table 2 : rm_dummy(customer, weekno, imputed)
The imputed column in table one is null(all columns).
I want to set "imputed" column in table 1 with the value of "imputed" in table two where customer and weekno match....
below the query I wrote.....but it is taking forever to execute...
update rm_example e
set e.imputed =
(select imputed
from rm_dummy d
inner join rm_example e on e.customer=d.customer and e.weekno=d.weekno)...
Is something wrong with the query?
I am working on remote database using sqldeveloperplus...and we are talking about million rows.
MERGE is usually quite a bit faster than an UPDATE with a subquery (the syntax might seem a little bit weird, but you'll get used to it); this assumes rm_example has a primary key column PK:
MERGE INTO rm_example target
USING
(SELECT e.pk as e_pk,
d.imputed
FROM rm_dummy d
INNER JOIN rm_example e ON e.customer=d.customer AND e.weekno=d.weekno) src
ON (target.pk = src.e_pk)
WHEN MATCHED THEN UPDATE
SET target.imputed = src.imputed;
Not sure if it will be faster than what you have done already but you try this
UPDATE
(SELECT e.imputed, d.imputed
FROM rm_example e
INNER JOIN rm_dummy d ON e.customer = d.customer AND e.weekno = d.weekno)
SET e.imputed = d.imputed;
After reading 8 Bulk Update Methods Compared (Oracle) I see this is really a Deprecated method that a MERGE syntax should be used. But in saying that depending on your system this could possibly have better performance

Determining best method to traverse a table and update another table

I am using Delphi 7, BDE, and Interbase (testing), Oracle (Production).
I have two tables (Master, Responses)
I need to step through the Responses table, use its Master_Id field to look it up in Master table (id) for matching record and update a date field in the Master table with a date field in the Responses table
Can this be done in SQL, or do i actually have to create two TTables or TQueries and step through each record?
Example:
Open two tables (Table1, Table2)
with Table1 do
begin
first;
while not EOF do
begin
//get master_id field
//locate in id field in table 2
//edit record in table 2
next;
end;
end;
thanks
One slight modification to Chris' query, throw in a where clause to select only the records that need the update. Otherwise it will set the rest of the dates to NULL
UPDATE Master m
SET
m.date = (SELECT r.date FROM Reponses r WHERE r.master_id = m.id)
WHERE m.id IN (SELECT master_id FROM Responses)
Updated to use aliases to avoid confusion which col comes from which table.
This is not ready made, copy-past'able query as UPDATE syntax differs from database to database.
You may need to consult your database sql reference for JOIN in UPDATE statement syntax.
When there are multiple responses to same master entry
UPDATE Master m
SET m.date = (
SELECT MAX(r.date) FROM Reponses r WHERE r.master_id = m.id)
WHERE m.id IN (SELECT master_id FROM Responses)
I used MAX() you can use whatever suits your business.
Again invest some time understanding SQL. Its hardly a few days effort. Get PLSQL Complete reference if you are into Oracle
Try this SQL (changing names to fit your situation)
UPDATE Master m
SET date = ( SELECT date FROM Responses WHERE id = m.id )