How to update joined table using condition - postgresql

I'm having an issue with a simple update statement. I'm new to postgresql and I'm still stuck on MS Sql Server syntax.
What I want to do is to update all records from table1 which are not present / don't exist in table2. Table1 and Table2 are having an 1 to 1 relation. The join column is "colx" from my example
On Ms SQL Server I would have something like this:
UPDATE table1 set col1='some value' from table1 t1 LEFT JOIN table2 t2 on t1.colx=t2.colx WHERE t2.colx IS NULL
or
UPDATE table1 set col1='some value' from table1 t1 where not exists (select 1 from table2 t2 where t1.colx=t2.colx)
My issue is when performing the same on PostgreSql it updates all records from table1, not only the records matching the condition (e.g. I was expecting 4 records to be updated, but all records from table1 are updated instead).
I checked using a select statement the join condition for all possible approaches and I have the expected result (e.g. 4 records).
Is there anything I'm missing?

Your question is not very clear about the requirement.
What I understood is you want to update the value of col1 in table1 for those records which are not present in the table2.
You can try it this way in Postgresql:
UPDATE table1 t1 set col1='some value' where not exists(select 1 from table2 where colx=t1.colx)
DEMO

Related

I am trying to run a postgresql query in which I need to join three tables as part of update query but it is giving me error on join

I am trying to run a postgresql query in which I need to join three tables as part of update query but it is giving me error on join.
UPDATE table1
join table2 on (table1.id=table2.id1)
join table3 on (table2.id2=table3.id)
SET table1.name='Test',
table3.equipment_code='ABC'
WHERE table1.id='21003';
Can you please guide me accordingly?
Not tested but something like this:
UPDATE table1
SET table1.name='Test'
FROM
table1 join table2 on table1.id=table2.id1
table2 join table3 on table2.id2=table3.id
WHERE
table3.equipment_code='ABC'
AND
table1.id='21003';
Though I am not sure why you are not just doing:
UPDATE table1
SET table1.name='Test'
WHERE
table1.id='21003';
I don't see that table2 and table3 are contributing anything to the UPDATE.
you can only update one table per update query.
so what you need is two separate queries like this:
1- update table3 using table1
UPDATE table3 SET equipment_code = t.whatever
FROM (SELECT * FROM table1 JOIN table2 ON table1.id = table2.id1) AS t
WHERE t.id2 = table3.id AND table1.id = '21003';
2- then update your table1
UPDATE table1 SET name = 'Test' WHERE id = '21003';
btw if you wanna know more about the update-join syntax visit here: https://www.postgresqltutorial.com/postgresql-update-join/

How to write a Postgres SELECT FOR UPDATE when using the EXCEPT set operator?

In Postgres (11, if it matters), I need to do a SELECT FOR UPDATE to obtain a collection of rows that I'll subsequently be doing some alterations on, and which I don't want anyone outside my transaction messing with while I do those alterations.
However, the set of rows I want to lock is actually defined by a set-difference, i.e.,
SELECT <columns> FROM table1 t1 JOIN table2 t2 ON ... WHERE ...
EXCEPT
SELECT <columns> FROM table1 t1 JOIN table3 t3 ON ... WHERE ...
I want the result-set of this set-difference to determine the set of rows that get locked; that is, those rows that are selected by the second SELECT should ideally not get locked.
But I'm not quite sure where to put the FOR UPDATE clause to achieve this. It seems like putting the FOR UPDATE immediately after either of the SELECT lines above would not give me what I want. And in fact I suspect that I can't legally put it after the first of those SELECT lines (i.e., just before the EXCEPT).
One idea that occurred to me was to parenthesize the second SELECT (the one that's the subject of the EXCEPT), so that the FOR UPDATE won't be interpreted as part of that second SELECT:
SELECT <columns> FROM table1 t1 JOIN table2 t2 ON ... WHERE ...
EXCEPT
(SELECT <columns> FROM table1 t1 JOIN table3 t3 ON ... WHERE ...)
FOR UPDATE
But I'm not sure that that gives me what I want either, even if it turns out to be syntactically acceptable.
It's possible that if I had an idea of the shape of the parse tree for a (Postgres) select statement, I could easily figure this out myself; but as it is, I'm a bit lost right now.
You cannot use FOR UPDATE together with UNION, INTERSECT or EXCEPT, because this could cause ambiguities in the general case.
I can think of two approaches:
Use EXISTS and NOT EXISTS:
SELECT ... FROM table1
WHERE EXISTS (SELECT 1 FROM table2 ...
WHERE table2.x = table1.x AND ...)
AND NOT EXISTS (SELECT 1 FROM table3 ...
WHERE table3.y = table1.y AND ...)
FOR UPDATE OF table1;
Use a subquery:
SELECT ... FROM table1
WHERE id IN (SELECT t1.id
FROM table1 t1 JOIN table2 t2 ON ...
WHERE ...
EXCEPT
SELECT t1.id
FROM table1 t1 JOIN table3 t3 ON ...
WHERE ...)
FOR UPDATE OF table1;

Dynamic values to another SQL statement

Is there a way to combine two SQL queries into a single SELECT query in PostgreSQL?
My requirements are as follows:
SELECT id FROM table1;
SELECT name FROM table2 WHERE table2.id = table1.id;
I think I need to pass values of table1.id in as some sort of dynamic values (loop values) for use in the SELECT statement executed on table2. What is the easiest way to solve this problem, is it possible to do this with stored procedures or functions in PostgreSQL?
select t1.id, name
from
table1 t1
inner join
table2 t2 using (id)
where t1.id = 1

Insert data into table effeciently, postgresql

I am new to postgresql (and databases in general) and was hoping to get some pointers on improving the efficiency of the following statement.
I am inserting data from one table to another, and do not want to insert duplicate values. I have a rid (unique identifier in each table) that are indexed and are Primary Keys.
I am currently using the following statement:
INSERT INTO table1 SELECT * FROM table2 WHERE rid NOT IN (SELECT rid FROM table1).
As of now the table one is 200,000 records, table2 is 20,000 records. Table1 is going to keep growing (probably to around 2,000,000) and table2 will stay around 20,000 records. As of now the statement takes about 15 minutes to run. I am concerned that as Table1 grows this is going to take way to long. Any suggestions?
This should be more efficient than your current query:
INSERT INTO table1
SELECT *
FROM table2
WHERE NOT EXISTS (
SELECT 1 FROM table1 WHERE table1.rid = table2.rid
);
insert into table1
select t2.*
from
table2 t2
left join
table1 t1 on t1.rid = t2.rid
where t1.rid is null

GROUP BY in UPDATE FROM clause

I really need do something like that:
UPDATE table t1
SET column1=t2.column1
FROM table t2
INNER JOIN table t3
USING (column2)
GROUP BY t1.column2;
But postgres is saying that I have syntax error about GROUP BY clause. What is a different way to do this?
The UPDATE statement does not support GROUP BY, see the documentation. If you're trying to update t1 with the corresponding row from t2, you'd want to use the WHERE clause something like this:
UPDATE table t1 SET column1=t2.column1
FROM table t2
JOIN table t3 USING (column2)
WHERE t1.column2=t2.column2;
If you need to group the rows from t2/t3 before assigning to t1, you'd need to use a subquery something like this:
UPDATE table t1 SET column1=sq.column1
FROM (
SELECT t2.column1, column2
FROM table t2
JOIN table t3 USING (column2)
GROUP BY column2
) AS sq
WHERE t1.column2=sq.column2;
Although as formulated that won't work because t2.column1 isn't included in the GROUP BY statement (it would have to be an aggregate function rather than a simple column reference).
Otherwise, what exactly are you trying to do here?
In MariaDB/ MySQL this SQL work :
UPDATE table t1 left join (
SELECT t2.column1, column2
FROM table t2
JOIN table t3 USING (column2)
GROUP BY column2
) AS sq on t1.column2=sq.column2
SET column1=sq.column1;