Update multiple fields in a table - postgresql

I have been trying to update multiple fields value in transsit column in the table tracking_details.
I have a table named tracking_details and which consist of two columns id and transsit
Example tracking_details table:-
id | transsit
------------------
1 | rec
2 | rec
3 | sen
4 |
5 | rec
Here, I would like to change rec to received where id equal 1,2 and 5
And what I have done so far is:
UPDATE tracking_details
SET transsit = 'received'
WHERE id = (select id from tracking_details where transsit='rec');
Then I got the following error:
ERROR: more than one row returned by a subquery used as an expression
********** Error **********
ERROR: more than one row returned by a subquery used as an expression
SQL state: 21000

UPDATE tracking_details
SET transsit = 'received'
WHERE id IN (select id from tracking_details where transsit='rec');
For multiple row update use IN instead of = because = will always have only one row or simply you can use join.
UPDATE tracking_details a
JOIN tracking_details b
ON a.id=b.id
SET a.transsit = 'received'
Where b.transsit='rec';
Furthurmore looking at query you do it using single query
UPDATE tracking_details
SET transsit = 'received'
WHERE transsit='rec';

You can simply do an UPDATE with a WHERE clause:
UPDATE tracking_details
SET transsit = 'received'
WHERE transsit = 'rec';

Related

PL/SQL error ORA-00904: invalid identifier using merge, select and set

I'm new to PL/SQL. I've created a table called orders which has a pk as orders_id and a products table with a pk as products_id. Both are numbers 1 through 10. In the orders table is a column called item_name, which I want to merge into the products column called item_name.
This is what I have tried:
MERGE INTO products
USING (
SELECT item_name
FROM orders)
ON (orders.order_id = products.product_id)
WHEN MATCHED THEN
UPDATE SET
products.item_name = orders.item_name
AND
MERGE INTO products
USING (
SELECT item_name
FROM orders)
ON (products.product_id=orders.order_id )
WHEN MATCHED THEN
UPDATE SET
products.item_name2 = orders.item_name
I keep getting the error "ORA-00904: "ORDERS"."ORDER_ID": invalid identifier". I've checked order_id is a NUMBER the same as the product_id. I have also created a column in products called item_name2, but that didn't work either. What does the error mean? Any help is appreciated, thank you.
Here's how.
Sample tables:
SQL> select * from orders;
ORDERS_ID ITEM_N
---------- ------
1 Name A
2 Name B
3 Name C
5 Name E
SQL> select * from products;
PRODUCTS_ID ITEM_NAME
----------- ----------
1
2
3
4
Updating products.item_name from the orders table:
SQL> merge into products p
2 using orders o
3 on (o.orders_id = p.products_id)
4 when matched then update set
5 p.item_name = o.item_name;
3 rows merged.
Result:
SQL> select * from products;
PRODUCTS_ID ITEM_NAME
----------- ----------
1 Name A
2 Name B
3 Name C
4 --> no matching IDs, so it is left empty
SQL>

Multiple UPDATE ... FROM same row is not working

I'm trying to do multiple update, but it works only for the first row.
I have table "users" with 2 records:
create table users
(
uid serial not null
constraint users_pkey
primary key,
balance numeric default 0 not null
);
INSERT INTO public.users (uid, balance) VALUES (2, 100);
INSERT INTO public.users (uid, balance) VALUES (1, 100);
I try to UPDATE user "1" twice with the query, but it update only one time:
balance for user "1" become "105", not "115"
update users as u
set balance = balance + c.bal
from (values (1, 5),
(1, 10)
) as c(uid, bal)
where c.uid = u.uid;
Why it not updated for all rows from subquery?
The postgresql documentation gives no reason for this behaviour but does specify it.
Relevant quote
When a FROM clause is present, what essentially happens is that the
target table is joined to the tables mentioned in the from_list, and
each output row of the join represents an update operation for the
target table. 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.
Use a SELECT with a GROUP BY to combine the rows before performing the update.
You need to aggregate in the inner query before joining:
update users as u
set balance = balance + d.bal
from (
select uid, sum(bal) bal
from ( values (1, 5), (1, 10) ) as c(uid, bal)
group by uid
) d
where d.uid = u.uid;
Demo on DB Fiddle:
| uid | balance |
| --- | ------- |
| 2 | 100 |
| 1 | 115 |

How to execute an update statement with where clause having select statement

I have a table (student) with the following schema in postgres 9.5:
id | marks | division | class
1 90 A 1
2 90 B 2
3 90 B 1
I want to update divisions of student with class 1 and marks = 90 to "A".
I know I can simply use update student set division='A' where class =1 and marks=90
But this to understand how to use a select statement returning multiple rows in the query. Somethig like:
update student set division ='A' where id=(select id from student where class=1 and marks=90)
I am new to postgres. Some pointers will help.
You don't need a sub-select:
update student
set division = 'A'
where class = 1
and marks = 90;
But if you insist on using a sub-select you need an IN:
update student
set division = 'A'
where id in (select id
from student
where class = 1
and marks = 90);

Does the returning clause always execute first?

I have a many-to-many relation representing containers holding items.
I have a primary key row_id in the table.
I insert four rows: (container_id, item_id) values (1778712425160346751, 4). These rows will be identical except the aforementioned unique row_id.
I subsequently execute the following query:
delete from contains
where item_id = 4 and
container_id = '1778712425160346751' and
row_id =
(
select max(row_id) from contains
where container_id = '1778712425160346751' and
item_id = 4
)
returning
(
select count(*) from contains
where container_id = '1778712425160346751' and
item_id = 4
);
Now I expected to get 3 returned from this query, but I got a 4. Getting a 4 is the desired behavior, but it is not what was expected.
My question is: can I always expect that the returning clause executes before the delete, or is this an idiosyncrasy of certain versions or specific software?
The use of a query in returning section is allowed but not documented. For the documentation:
output_expression
An expression to be computed and returned by the DELETE command after each row is deleted. The expression can use any column names of the table named by table_name or table(s) listed in USING. Write * to return all columns.
It seems logical that the query sees the table in a state before deleting, as the statement is not completed yet.
create temp table test as
select id from generate_series(1, 4) id;
delete from test
returning id, (select count(*) from test);
id | count
----+-------
1 | 4
2 | 4
3 | 4
4 | 4
(4 rows)
The same concerns update:
create temp table test as
select id from generate_series(1, 4) id;
update test
set id = id+ 1
returning id, (select sum(id) from test);
id | sum
----+-----
2 | 10
3 | 10
4 | 10
5 | 10
(4 rows)

apply sequence values to ordered subset of table records

I have a table "dummy" with the following columns:
| id | name | position | updated_at | status |
I want to update the column "position" with values from a sequence, only for the records with status=active and ordered desc by "updated_at".Is this possible ?
A close query, but not valid because of the 'order by' clause, is:
Update dummy d1 set position = nextval('positions_sequence')
from dummy d2 where d1.id = d2.id and d2.status = 'active'
order by d2.updated_at desc
You can easily archieve this with stored proc using loop:
FOR d1 IN SELECT * FROM dummy WHERE status = active order by updated_at desc LOOP
new_position := nextval('positions_sequence');
EXECUTE Update dummy set position = new_position where id = d1.id;
END LOOP;