What is the expected match if more than one rows match on a join condition performing an update operation in postgresql? - sql

Consider a query of this sort:
UPDATE table1 SET attr1 = table2.attr1 FROM table2 WHERE table1.attr3 = table2.attr3
Supposing there are duplicate attr3s in table2 and hence more than one rows that have a match with one single row of attr3 in table1, which row's attr1 will be assigned as table1's attr1?
I tried using an order by expecting that it will pick up the first match but I see that different matches are being picked up in different instances. Please let me know if I should add a sample data set if I did not make the scenario clear.

It always helps to read the manual:
In other words, a target row shouldn't join to more than one row from the other table(s). If it does, then only one of the join rows will be used to update the target row, but which one will be used is not readily predictable
(emphasis mine)
So the anwer to your question is: it's unpredictable

Related

MS SQL - Conditional UPDATE return result

I have a stored procedure which is doing the following.
The populated target table data is checked against several similar source tables for a match (based on name and address data). If a match is found in the first table then it updates the target with a flag identifying which source table the match was from. However if it doesn't find a match I need it to look in the next source table and the next until either a match is found or not as the case may be.
Is there an easy way for the UPDATE statement to provide some kind of return value I can query to say whether it updated the target table? I would like to use this return value so that I can skip checking subsequent source tables unnecessarily.
Otherwise will I have to perform the conditional UPDATE then do a separate query to determine if the UPDATE actually updated the flag?
Probably the safest approach is to use the OUTPUT clause. This will return the modified rows into a new table.
You can check the table to see if any rows have been updated.
One advantage of the OUTPUT clause is that you can update multiple rows at the same time.
I like the soulution of Gordon, but I do not think you actualy need it.
Simply run the updates in order:
UPDATE BASE_TABLE
SET FLAG='first_table'
where FLAG IS null AND
EXIST (SELECT 1 FROM first_table f1 where f1.ID = ID)
UPDATE BASE_TABLE
SET FLAG='second_table'
where FLAG IS null AND
EXIST (SELECT 1 FROM second_table f2 where f2.ID = ID)
...
And so on.
You dont need to check every row conditionaly, that would be very slow.
you can put your update in try/catch and insert your result to another table

IBM DB2 update using JOIN

I need to update a table containing orders depending on customer information. This is how i would have approached it but apparently DB2 doesnt support JOINs in UPDATEs. I am working on an IBM iSeries.
UPDATE lib.orders as o
JOIN lib.customers as c
ON o.cstmrid = c.id
SET o.updatehere = 'NEWVALUE'
WHERE c.info = 'VALUE'
There are allready questions on that topic but none really help me.
Thanks!
Okay so this is really late but in case someones reading this: none of the comments/answers were correct. The important point is that i am working on an iseries which uses db2 udb and does neither support joins on updates nor merge (at least the version we work with).
The only way i figured out will work is a WHERE EXISTS clause.
I would recommend something like:
UPDATE lib.orders
SET updatehere = 'NEWVALUE'
WHERE cstrmid in (
SELECT id
FROM lib.customers
WHERE info = 'VALUE'
)
The reality is that an update statement has four main pieces:
what table is being updated?
possibly with an alias specified
your example used one
my suggestion didn't need one
what field(s) is/are being updated within item 1?
can be a single field, as in your example
can be a tuple, containing multiple fields
what value(s) is/are being populated into item 2?
can be a single value or a tuple of values, depending on item 2
can be the result of a subquery
must return a single value or a tuple, as needed, to match item 2
can join against the table specified in item 1 to ensure different values are output for different rows in the item 1's table
what matching criteria are there for records in item 1?
can be one or more criteria
if you don't specify this, DB/2 will iterate through ALL records in the table
can include a subquery
if you have a subquery in item 3, and a row matching this doesn't match up with any results from that subquery, item 2's fields will be assigned null values
I specified item 1 in line 1 of my suggestion.
I specified items 2 and 3 on line 2 of my suggestion.
I specified item 4 using a subquery in lines 3 - 7
I have, on occasion, written update statements where:
item 2 was a tuple of multiple fields
item 3 was a subquery which returned multiple values, joining against the table specified in item 1
item 4 used a subquery similar to what was used in item 3 but returning join values instead of update values for fields
The result was that DB/2 queried against item 1, using item 4 as criteria and then iterated through the resulting rows, updating fields in item 2 against values returned from item 3. As item 3 was a subquery, the join against the table alias specified in item 1 provided necessary criteria for what was returned from the subquery.
I've written update statements where the subqueries in question were Table Value Constructors. In that fashion, I was able to update a hundreds of records based on a small set of known values.
I have done all of this on DB/2 on an iSeries. I never used a MERGE because, as you've noticed, not all versions of DB/2 support that.

How to update multiple matching records with data from another table

Working with DB2 but guess this applies to SQL in general.
I have two tables; Table1 contains data where the Fix column could be same in multiple rows. Table2 has unique rows and has data I want to add to columns in the first table if one or more matches between the Fix column in Table1 and the Title column in Table2 are found.
I'm getting an issue in that the SQL is returning an error saying: "The same row of target table "xxxxxxx" was identified more than once for an update, delete or insert operation of the MERGE statement.."
Now that is expected ie I know there are multiple rows in the target table that match the criteria and need to have the data from the source table applied to them.
I'm using MERGE but is that just not going to be possible? Been looking at GROUP BY too but can't get it to work.
If I was doing this in another language I'd go through the source table, build a collection of matching records from the source then iterate through the collection updating that with the source data that needed adding. Thinking there is a more efficient way in SQL though?
This code is completely wrong (and returns the error above) but adding it here to help any good person who wants to lend a hand :-)
CREATE PROCEDURE Update_RawData_With_xKey_Data ()
P1: BEGIN
MERGE INTO table1 AS T
USING table2 AS S
ON (T.FIX = S.TITLE)
WHEN MATCHED THEN
UPDATE SET
T.Rating = S.Rating,
T.GSDS = S.GSDS_Date,
ELSE IGNORE ;
END P1

Is UPDATE without a JOIN possible?

I am trying to update a single column (all rows) from one table with a single value from another table. The problem is there is no index fields to join the tables on. Here is an example of the tables/columns in question (without data):
Table1: ID, Name, Address, Telephone, PriceList
Table2: PriceList, Description
I want to update Table1.Pricelist with the value in Table2.Pricelist
The current data I am testing with has one row in Table2 but it is possible for there to be more. In that case, I would just use the first value returned.
I thought I would post here to get the definitive answer as to whether this is possible.
update table1
set pricelist= (select top(1) table2.pricelist from table2);
UPDATE Table1
SET Pricelist = DLookup("PriceList", "Table2");
The DLookup expression will return a single value from Table2. So when Table2 contains only one row, it will give you the "first" PriceList value. However, with more rows in Table2, DLookup will still return one value but that may not come from the row which you consider to be the "first" row.
It would help to know how to identify which target row contains the PriceList value you want to use in the UPDATE.

Update all rows of a single column

I'm dealing with two tables which have 2 columns, as listed under.
Table 1: table_snapshot
account_no | balance_due
Table 2: table_ paid
account_no | post_balance | delta_balance
I added a third column to table2 with the following command:
ALTER TABLE table_paid ADD delta_balance number(18);
I'm trying to use the following query, to update the new column ( delta_balance ) with the difference in balances between 1 and 2.
FYI, table_paid is a subset of table_snapshot. i,e., table 2 has only a few accounts present in table 1. I get an error saying : SQL Statement not properly ended. the query i'm using is:
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance - table_snapshot.balance_due
from table_paid, table_snapshot
WHERE table_paid.account_no = table_snapshot.account_no;
Appreciate if someone can correct my query.
Many thanks.
novice.
Oracle doesn't have the UPDATE ... FROM syntax that you're using from MS Sql Server (which, I believe, isn't ANSI anyway). Instead, when you need to do an update on a result set, Oracle has you create the resultset as a kind of inline view, then you update through the view, like so:
UPDATE ( SELECT tp.delta_balance
, tp.post_balance
, ts.balance_due
FROM table_paid tp
JOIN table_snapshot ts
ON tp.account_no = ts.account_no
)
SET delta_balance = post_balance - balance_due;
This is more "correct" than the answers supplied by Babar and palindrom, as their queries will update every row in table_paid, even if there are no corresponding rows in table_snapshot. If there is a 1-1 correspondance, you don't need to worry, but it's safer to do it with the inline view.
It's unclear from your example which table is the parent table, or (as I'm guessing) neither is the parent table and account_no is pointing to the primary key of another table (presumably account, or "table_account" by your naming conventions). In any case, it's clear that there is not a 1-1 correspondence in your table - 15K in one, millions in the other.
This could mean 2 things: either there are many rows in table_snapshot that have no corresponding row in table_paid, or there are many rows in table_snapshot for each row in table_paid. If the latter is true, your query is impossible - you will have multiple updates for each row in table_paid, and the result will be unpredictable; how will you know which of the "post_balance - balance_due" expressions will ultimately determine the value of a given delta_balance?
If you run my query, you will find this out quickly enough - you will get an error message that says, "ORA-01779: cannot modify a column which maps to a non key-preserved table". This error will appear based not on the data in the table (it may be okay), but based on the primary keys you have defined on the two tables. If the join condition you specify doesn't unambiguously result in a 1-1 relationship between the updated table and the rest of the join, based on the defined keys, you will get this error. It's Oracle's way of telling you, "You're about to screw up your data".
In the other answers here, you will only get an error (in that case, ORA-01427: single-row subquery returns more than one row) if you actually have data that would cause a problem; my version is more strict, so it may turn out that you will need to use the other versions.
And, as the others have said, you'll definitely want an index on account_no for the table_snapshot table. One on the table_paid wouldn't hurt either.
Try this
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance -
(SELECT table_snapshot.balance_due from table_snapshot WHERE table_paid.account_no =
table_snapshot.account_no);
UPDATE table_paid
SET table_paid.delta_balance = table_paid.post_balance - ( select balance_due from table_snapshot
WHERE table_paid.account_no = table_snapshot.account_no )