I want this stored procedure to work concurrently, but as I see in PgAdmin it doesn't. One process is blocked by another one (waits him to finish). Seems to me, update query has no problems with being running concurrently. So this is all about INSERT, am I right? I tried to set ROW SHARE EXCLUSIVE LOCK on update query, but I've reached deadlock.
UPDATE product p SET category_id = m.internal_category_id, category_from=m.cat_prior FROM main_table m
WHERE p.mpn=m.mpn AND
p.vendor_id = m.internal_vendor_id AND
m.new_prod=false and
m.internal_category_id IS NOT NULL AND
(category_from is null or category_from<=m.cat_prior);
INSERT INTO product(vendor_id, category_id, mpn, name, category_from)
SELECT DISTINCT ON(m.mpn, m.internal_vendor_id) m.internal_vendor_id, m.internal_category_id, m.mpn, m.prod_name, m.cat_prior
FROM main_table m
LEFT OUTER JOIN product ON product.mpn=m.mpn AND product.vendor_id=m.internal_vendor_id
WHERE m.new_prod='1' AND m.internal_vendor_id IS NOT NULL
AND product.mpn IS NULL;
UPDATE main_table m SET internal_product_id = p.id
FROM product p
WHERE p.mpn=m.mpn AND p.vendor_id = m.internal_vendor_id ;
UPDATE vendor SET has_products = true FROM (SELECT DISTINCT v.id as id FROM vendor v INNER JOIN product p ON p.vendor_id = v.id) AS r WHERE vendor.id = r.id;
UPDATE vendor SET has_products = false FROM (SELECT DISTINCT v.id as id FROM vendor v LEFT JOIN product p ON p.vendor_id = v.id WHERE p.vendor_id IS NULL) AS r WHERE vendor.id = r.id;
Seems to me, update query has no problems with being running
concurrently. So this is all about INSERT, am I right?
Both can be problematic but UPDATE tends to be more problematic with regard to interlocking.
When an UPDATE modifies a row and another UPDATE tries to modify the same row, the second is put to wait until the first transaction commits or rolls back.
On the other hand, when two INSERTs hit the same table, the second one is made to wait only if there's a unique index on the table and both statements are trying to insert the same indexed value. Which is unusual because that would lead to an index violation error unless the first transaction aborts.
Just by looking at a piece of code, it's hard to know whether concurrent calls will hit the same rows or not, it depends on the data. However in your case it's a bit suspicious that your first UPDATE doesn't seem to take any parameter.
Related
Goal: Create a query to pull the closest cycle count event (Table C) for a product ID based on the inventory adjustments results sourced from another table (Table A).
All records from Table A will be used, but is not guaranteed to have a match in Table C.
The ID column will be present in both tables, but is not unique in either, so that pair of IDs and Timestamps together are needed for each table.
Current simplified SQL
SELECT
A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM
A
LEFT JOIN
C
ON A.LPID = C.LPID
WHERE
A.facility = 'FACID'
AND A.WHENOCCURRED > '23-DEC-22'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC
;
This is currently pulling the first hit on C.WHENOCCURRED on the LPID matches. Want to see if there is a simpler JOIN solution before going in a direction that creates 2 temp tables based on WHENOCCURRED.
I have a functioning INDEX(MATCH(MIN()) solution in Excel but that requires exporting a couple system reports first and is extremely slow with X,XXX row tables.
If you are using Oracle 12 or later, you can use a LATERAL join and FETCH FIRST ROW ONLY:
SELECT A.WHENOCCURRED,
A.LPID,
A.ITEM,
A.ADJQTY,
C.WHENOCCURRED,
C.LPID,
C.LOCATION,
C.ITEM,
C.QUANTITY,
C.ENTQUANTITY
FROM A
LEFT OUTER JOIN LATERAL (
SELECT *
FROM C
WHERE A.LPID = C.LPID
AND A.whenoccurred <= c.whenoccurred
ORDER BY c.whenoccurred
FETCH FIRST ROW ONLY
) C
ON (1 = 1) -- The join condition is inside the lateral join
WHERE A.facility = 'FACID'
AND A.WHENOCCURRED > DATE '2022-12-23'
AND A.ADJREASONABBREV = 'CYCLE COUNTS'
ORDER BY A.WHENOCCURRED DESC;
I have two columns in the same table that I want to join in Postgresql but for some reason I’m getting this error. Don’t know how to figure it out. Please help.
[42P01] ERROR: relation "a" does not exist
Position: 10
X table contains two pools(ABC,XYZ), ids, numbers and description. If an ID exists in one pool but not in the other, it should update description column to “ADD”. Pools need to be joined on number.
UPDATE A
SET A.Description = 'ADD'
FROM X AS A
LEFT JOIN X AS B ON B.number = A.number
AND B.id = 'ABC'
WHERE A.id = 'XYZ'
AND B.number IS NULL
AND A.Description IS NULL;
With standard SQL you can't do a join as part of an update, but what you can do is include a subquery to select the id's to update. The subquery can contain a join. I'm not entirely clear on what you're actually trying to accomplish, but you could do something like this:
UPDATE x SET description='ADD' WHERE number IN (
SELECT a.number FROM x AS a
LEFT OUTER JOIN x AS b ON a.number=b.number AND a.id='XYZ' AND b.id='ABC'
WHERE b.number IS NULL
);
This will join the table x with itself and will select (and update) any numbers's that don't have a matching number in the 'ABC' and 'XYZ' zone.
PostgreSQL does have a UPDATE FROM syntax that does let you update with complex subqueries. It's more flexible but it's non-standard. You can find an example of this type of query here.
Why is it, that if you use jsonb_set as new values in an UPDATE query, that it only updates the first row of the result set?
See this example here: http://sqlfiddle.com/#!17/0bdd8/5
There are two entries in reactions for the same post, yet when I try to assign a random value keyed to the username, it only inserts it for the first value not for the second one:
UPDATE posts
SET a_to_b = jsonb_set(posts.a_to_b, array[username::text], to_jsonb(random()))
FROM reactions
WHERE posts.id = reactions.post_id;
There are more than one row in the FROM clause for a single row to be modified. The documentation explains it clearly:
When using FROM you should ensure that the join produces at most one output row for each row to be modified. 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.
You can execute a single update by aggregating the expected value in a subquery. Use the aggregate function jsonb_object_agg():
update posts p
set a_to_b = agg
from (
select p.id, jsonb_object_agg(username, random()) as agg
from posts p
join reactions r on p.id = r.post_id
group by p.id
) s
where s.id = p.id;
SqlFiddle.
Alternatively, you can use an anonymous code block to repeatedly update a single row, e.g.:
do $$
declare rec record;
begin
for rec in
select *
from posts p
join reactions r on p.id = r.post_id
loop
update posts
set a_to_b = jsonb_set(a_to_b, array[rec.username], to_jsonb(random()))
where posts.id = rec.post_id;
end loop;
end $$;
The second solution may turn out to be suboptimal, especially for a large number of aggregated values.
In DB2, I need to do an insert, then, using results/data from that insert, update a related table. I need to do it on a million plus records and would prefer not to lock the entire database. So, 1) how do I 'couple' the insert and update statements? 2) how can I ensure the integrity of the transaction (without locking the whole she-bang)?
some pseudo-code should help clarify
STEP 1
insert into table1 (neededId, id) select DYNAMICVALUE, id from tableX where needed value is null
STEP 2
update table2 set neededId = (GET THE DYNAMIC VALUE JUST INSERTED) where id = (THE ID JUST INSERTED)
note: in table1, the ID col is not unique, so i can't just filter on that to find the new DYNAMICVALUE
This should be more clear (FTR, this works, but I don't like it, because I'd have to lock the tables to maintain integrity. Would be great it I could run these statements together, and allow the update to refer to the newAddressNumber value.)
/****RUNNING TOP INSERT FIRST****/*
--insert a new address for each order that does not have a address id
insert into addresses
(customerId, addressNumber, address)
select
cust.Id,
--get next available addressNumber
ifNull((select max(addy2.addressNumber) from addresses addy2 where addy2.customerId = cust.id),0) + 1 as newAddressNumber,
cust.address
from customers cust
where exists (
--find all customers with at least 1 order where addressNumber is null
select 1 from orders ord
where 1=1
and ord.customerId = cust.id
and ord.addressNumber is null
)
/*****RUNNING THIS UPDATE SECOND*****/
update orders ord1
set addressNumber = (
select max(addressNumber) from addresses addy3
where addy3.customerId = ord1.customerId
)
where 1=1
and ord1.addressNumber is null
The IDENTITY_VAL_LOCAL function is a non-deterministic function that returns the most recently assigned value for an identity column, where the assignment occurred as a result of a single INSERT statement using a VALUES clause
I'm trying to update fields from three different tables but I'm getting some errors:
UPDATE
a, b, c
SET
a.Locked = 0,
b.Locked = 0,
c.Locked = 0,
a.LockedByUsername = 'zolomon',
b.LockedByUsername = 'zolomon',
c.LockedByUsername = 'zolomon',
a.LockedAt = CURRENT_TIMESTAMP,
b.LockedAt = CURRENT_TIMESTAMP,
c.LockedAt = CURRENT_TIMESTAMP
FROM
TableA AS a
INNER JOIN TableB as b ON n.Objid = o.Objid
INNER JOIN TableC as c ON n.Namnid = e.Namnid
WHERE
a.Namn1 = 'FirstName LastName' AND b.objektkod='SomeIdentifier'
And the errors:
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near ','.
You can't update fields from multiple tables on a single update query. There error you are getting is because this is not permitted:
update a, b, c
Since you can only update one table per update command.
As pointed out by other answers, in SQL an UPDATE updates only one table. That's normally enough for most practical needs. If you want to update several tables at the same time, you can just put the updates inside a transaction, and the effect will normally be the same.
If you are concerned about getting different timestamps (for your field lockedAt) first look into your database docs to check if your CURRENT_TIMESTAMP function refers to the start time of the transaction (e.g. PostgreSQL).
you cannot update multiple tables in one statement. an option would be to use a stored procedure
We can update it with join like this
UPDATE table1
INNER join table2 on table1.id=table2.tab1_id
INNER join table3 on table1.id=table3.tab1_id
SET table1.status=1,table2.status=1,table3.status=1,table1.name='Premjith'
WHERE table1.id=1