need to replace subquery with JOIN - sql

I need to use join in below instead of Subquery.
can anybody help me to rewrite this with JOIN.
update Table1
set status = 'Edited'
where val_74 ='1' and status ='Valid'
and val_35 is not null
and (val_35,network_id) in
(select val_35,network_id from
Table2 where val_35 is not null
and status='Correct_1');
update Table1 b SET (Val_12,Val_13,Val_14)=
(select Val_12,Val_13,Val_14 from
(select Val_35,network_id, Val_12, Val_13, Val_14
from Table2
where Val_34 is not null
and (REGEXP_LIKE(Val_13,'^[0-9]+$'))
and (Val_14 is null or (REGEXP_LIKE(Val_14,'^[0-9]+$')))
group by Val_35,network_id,Val_12,Val_13,Val_14
)
where Val_35 = b.Val_35 and network_id = b.network_id and rownum=1
)
where status = 'PCStep2' and (regexp_like(Val_13,'[MSS]+') or regexp_like(Val_14,'[MSS]+'));
I tried a lot with my less Knowledge In SQL JOINs. but getting multiple erros.
can anybody help me with the queries at the earliest.
Hearty thanks in advance

Actually you can not mix a update statement with a join statement. An update statement always expects exactly one table definition after the update command.
-- ORA-00971: missing SET keyword
update orders o, customers c
set o.order_value = c.account_value
where o.cust_id = c.cust_id
-- works fine
update orders o
set o.order_value = (select c.account_value
from customers c
where c.id = o.cust_id)

Related

SQL Server - Code for Updating values using inner query self join

this may be quite basic for most, but I'd like to get some help.
Using SQL Server I have the following Orders table (Excel excerpt to simplify):
Please note there are multiple orders (OrderID). Some may have "PrimaryOrder" value, meaning they are related to an existing prior order. Related orders receive the "PrimaryOrder" of the 1st related order, and an "OrderIndex" noting the order they came in.
Only the first order in each set has value. If an order's "PrimaryOrder" is NULL, it means it is a single order and I should simply ignore it.
What I need is, using SQL Server Update command give all orders which are related, the same "value" as their 1st related order's "Value".
Meaning for each order that has "OrderIndex" > 1, update it's Value field from NULL to it's "PrimaryOrder" value.
If "PrimaryOrder" = 1 OR is NULL, ignore and don't update.
Tried some simple INNER JOIN but got lost.
I don't think it should be too complicated, but I might be overthinking it.
Thank you!
You can use correlated sub-query with update statement :
update o
set o.value = (select top (1) o1.value
from Orders o1
where o1.primaryorder = o.primaryorder and
o1.value is not null and
o1.orderindex <= o.orderindex
order by o1.orderindex desc
)
from Orders o
where o.value is null;
Perhaps something like this:
UPDATE #table
SET a.Value=b.Value
FROM #table a INNER JOIN #table b
on a.OrderID=b.PrimaryOrder and a.OrderIndex>1 and a.Value is NULL
UPDATE o
SET Value=MaxVals.MaxValue
FROM Orders o
INNER JOIN (
SELECT MAX(Value) AS MaxValue, PrimaryOrder
FROM Orders
WHERE PrimaryOrder IS NOT NULL
GROUP BY PrimaryOrder
) AS MaxVals ON MaxVals.PrimaryOrder=o.PrimaryOrder
WHERE o.Value IS NULL
Thank you all.
Managed to take something from all the above and this solved it:
UPDATE O
SET O.[Value] = B.[Value]
FROM Orders O INNER JOIN Orders B
ON O.PrimaryOrder = B.[PrimaryOrder] and O.OrderIndex > 1 and O.[Value] is NULL
AND B.[OrderIndex] = 1

single-row subquery returns more than one row in Redshift when I try to use CASE in UPDATE

I am trying to use a case statement with sub query in a Update statement but I am facing an Issue like
single-row sub query returns more than
Please find my Query which I tried
update r_gl.ac
set meeting_cost = case currency_code when 'IND'
then amount
else round(tgt.amount)
from r_gl.ac tgt
join
(
select distinct
a.frm_cur,
a.to_cur,
a.exch_rate
from b_gl.currncy_conv_dim a
join r_gl.ac b
on (a.frm_cur = 123 and a.to_cur = b.cur_cd and f_rate = 'ABC')
join b_gl.int_fg
on b.in_s=c.in_s and a.cal_sk = trunc(c.intact_dt_key,-2)
) src
on tgt.cur_cd=src.to_cur
)
end
Please help me to solve this issue
Your current CASE expression is missing its END. That aside, I see even bigger problems with your UPDATE statement. Redshift is based on an old version of Postgres, and hence I expect that it would adhere to the same syntax Postgres would use for an update join:
UPDATE table1 AS t1
SET some_column = t2.some_other_column
FROM table2 AS t2
WHERE t1.id = t2.id
Applying this syntax to your current query along with the fix for the CASE expression leaves us with the following:
update r_gl.ac tgt
set meeting_cost = case when currency_code = 'IND'
then tgt.amount
else round(tgt.amount) end
from
(
select distinct
a.frm_cur,
a.to_cur,
a.exch_rate
from b_gl.currncy_conv_dim a
inner join r_gl.ac b
on (a.frm_cur = 123 and a.to_cur = b.cur_cd and f_rate = 'ABC')
inner join b_gl.int_fg
on b.in_s=c.in_s and a.cal_sk = trunc(c.intact_dt_key,-2)
) src
where tgt.cur_cd = src.to_cur
The table to which you are joining r_gl.ac has no effect on the data being used to update, but rather would only affect the update by targeting certain rows. If this be not your intended logic, then you might have to rethink the entire query.

update multiple rows with joins

I have this query in postgresql:
select *
from A s
join B m on (s.id=m.id)
where m.key=4 and s.ran=some_input_from_user
This gives me all the rows that I need to update.
I want to set A.value to be 90 for all these rows.
It doesn't look like a standart update query
if I do...
Update A set value=90 where.....
then I can't do the join.
any ideas how to do it?
This is the basic update syntax for PostgreSQL where you are updating based on a join to another table:
update A s
set
value = 90
from B m
where
s.id = m.id and
m.key = 4 and
s.ran = some_input_from_user
The trick is you never use the alias in the lvalue for the set commands. In other words, value = 90 is not s.value = 90. It seems minor, but I'm pretty sure it will prevent your query from working. The rationale is if you are updating table A (alias s) then any fields you are updating are, de-facto, from table A -- no need to alias them, and to allow aliases would almost imply you could update something other than A with this statement, which you cannot.
You can definitely use them in the rvalues, so this would certainly be okay (if it were your desire to update A based on B):
update A s
set
value = m.salary * s.commission
from B m
where
s.id = m.id and
(s.value is null or
s.value != m.salary * s.commission)
Here is the query:
update a set value = 90
where exists (
select 1 from b
where a.id = b.id and b.key=4
and a.ran=some_input_from_user);
The above query will eliminate the requirement of reading table a twice.
Also you can use this query:
update a set value = 90
where a.id in
(select b.id from b
where a.id = b.id and b.key = 4
and a.ran=some_input_from_user);
TRY THIS
UPDATE A
SET A.VALUE = 90
from A
join B m on (A.id=m.id)
where m.key=4 and s.ran=some_input_from_user

Error FROM Clause on update sql (postgres) [duplicate]

Basically, I want to do this:
update vehicles_vehicle v
join shipments_shipment s on v.shipment_id=s.id
set v.price=s.price_per_vehicle;
I'm pretty sure that would work in MySQL (my background), but it doesn't seem to work in postgres. The error I get is:
ERROR: syntax error at or near "join"
LINE 1: update vehicles_vehicle v join shipments_shipment s on v.shi...
^
Surely there's an easy way to do this, but I can't find the proper syntax. So, how would I write this In PostgreSQL?
The UPDATE syntax is:
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table [ [ AS ] alias ]
SET { column = { expression | DEFAULT } |
( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
[ FROM from_list ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
In your case I think you want this:
UPDATE vehicles_vehicle AS v
SET price = s.price_per_vehicle
FROM shipments_shipment AS s
WHERE v.shipment_id = s.id
Or if you need to join on two or more tables:
UPDATE table_1 t1
SET foo = 'new_value'
FROM table_2 t2
JOIN table_3 t3 ON t3.id = t2.t3_id
WHERE
t2.id = t1.t2_id
AND t3.bar = True;
The answer of Mark Byers is the optimal in this situation.
Though in more complex situations you can take the select query that returns rowids and calculated values and attach it to the update query like this:
with t as (
-- Any generic query which returns rowid and corresponding calculated values
select t1.id as rowid, f(t2, t2) as calculatedvalue
from table1 as t1
join table2 as t2 on t2.referenceid = t1.id
)
update table1
set value = t.calculatedvalue
from t
where id = t.rowid
This approach lets you develop and test your select query and in two steps convert it to the update query.
So in your case the result query will be:
with t as (
select v.id as rowid, s.price_per_vehicle as calculatedvalue
from vehicles_vehicle v
join shipments_shipment s on v.shipment_id = s.id
)
update vehicles_vehicle
set price = t.calculatedvalue
from t
where id = t.rowid
Note that column aliases are mandatory otherwise PostgreSQL will complain about the ambiguity of the column names.
Let me explain a little more by my example.
Task: correct info, where abiturients (students about to leave secondary school) have submitted applications to university earlier, than they got school certificates (yes, they got certificates earlier, than they were issued (by certificate date specified). So, we will increase application submit date to fit certificate issue date.
Thus. next MySQL-like statement:
UPDATE applications a
JOIN (
SELECT ap.id, ab.certificate_issued_at
FROM abiturients ab
JOIN applications ap
ON ab.id = ap.abiturient_id
WHERE ap.documents_taken_at::date < ab.certificate_issued_at
) b
ON a.id = b.id
SET a.documents_taken_at = b.certificate_issued_at;
Becomes PostgreSQL-like in such a way
UPDATE applications a
SET documents_taken_at = b.certificate_issued_at -- we can reference joined table here
FROM abiturients b -- joined table
WHERE
a.abiturient_id = b.id AND -- JOIN ON clause
a.documents_taken_at::date < b.certificate_issued_at -- Subquery WHERE
As you can see, original subquery JOIN's ON clause have become one of WHERE conditions, which is conjucted by AND with others, which have been moved from subquery with no changes. And there is no more need to JOIN table with itself (as it was in subquery).
For those actually wanting to do a JOIN you can also use:
UPDATE a
SET price = b_alias.unit_price
FROM a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value'
AND a.id = a_alias.id;
You can use the a_alias in the SET section on the right of the equals sign if needed.
The fields on the left of the equals sign don't require a table reference as they are deemed to be from the original "a" table.
For those wanting to do a JOIN that updates ONLY the rows your join returns use:
UPDATE a
SET price = b_alias.unit_price
FROM a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value'
AND a.id = a_alias.id
--the below line is critical for updating ONLY joined rows
AND a.pk_id = a_alias.pk_id;
This was mentioned above but only through a comment..Since it's critical to getting the correct result posting NEW answer that Works
Here we go:
update vehicles_vehicle v
set price=s.price_per_vehicle
from shipments_shipment s
where v.shipment_id=s.id;
Simple as I could make it.
To add something quite important to all the great answers above, when you want to update a join-table, you may have 2 problems:
you cannot use the table you want to update to JOIN another one
Postgres wants a ON clause after the JOIN so you cannot only use where clauses.
This means that basically, the following queries are not valid:
UPDATE join_a_b
SET count = 10
FROM a
JOIN b on b.id = join_a_b.b_id -- Not valid since join_a_b is used here
WHERE a.id = join_a_b.a_id
AND a.name = 'A'
AND b.name = 'B'
UPDATE join_a_b
SET count = 10
FROM a
JOIN b -- Not valid since there is no ON clause
WHERE a.id = join_a_b.a_id
AND b.id = join_a_b.b_id
a.name = 'A'
AND b.name = 'B'
Instead, you must use all the tables in the FROM clause like this:
UPDATE join_a_b
SET count = 10
FROM a, b
WHERE a.id = join_a_b.a_id
AND b.id = join_a_b.b_id
AND a.name = 'A'
AND b.name = 'B'
It might be straightforward for some but I got stuck on this problem wondering what's going on so hopefully, it will help others.
Here's a simple SQL that updates Mid_Name on the Name3 table using the Middle_Name field from Name:
update name3
set mid_name = name.middle_name
from name
where name3.person_id = name.person_id;
The link below has a example that resolve and helps understant better how use update and join with postgres.
UPDATE product
SET net_price = price - price * discount
FROM
product_segment
WHERE
product.segment_id = product_segment.id;
See: http://www.postgresqltutorial.com/postgresql-update-join/
First Table Name: tbl_table1 (tab1).
Second Table Name: tbl_table2 (tab2).
Set the tbl_table1's ac_status column to "INACTIVE"
update common.tbl_table1 as tab1
set ac_status= 'INACTIVE' --tbl_table1's "ac_status"
from common.tbl_table2 as tab2
where tab1.ref_id= '1111111'
and tab2.rel_type= 'CUSTOMER';
To UPDATE one Table using another, in PostGRE SQL / AWS (SQL workbench).
In PostGRE SQL, this is how you need to use joins in UPDATE Query:
UPDATE TABLEA set COLUMN_FROM_TABLEA = COLUMN_FROM_TABLEB FROM TABLEA,TABLEB WHERE FILTER_FROM_TABLEA = FILTER_FROM_TABLEB;
Example:
Update Employees Set Date_Of_Exit = Exit_Date_Recorded , Exit_Flg = 1 From Employees, Employee_Exit_Clearance Where Emp_ID = Exit_Emp_ID
Table A - Employees Columns in Table A - Date_Of_Exit,Emp_ID,Exit_Flg Table B is - Employee_Exit_Clearance Columns in Table B - Exit_Date_Recorded,Exit_Emp_ID
1760 rows affected
Execution time: 29.18s
--goal: update selected columns with join (postgres)--
UPDATE table1 t1
SET column1 = 'data'
FROM table1
RIGHT JOIN table2
ON table2.id = table1.id
WHERE t1.id IN
(SELECT table2.id FROM table2 WHERE table2.column2 = 12345)
The first way is slower than the second way.
First:
DO $$
DECLARE
page int := 10000;
min_id bigint; max_id bigint;
BEGIN
SELECT max(id),min(id) INTO max_id,min_id FROM opportunities;
FOR j IN min_id..max_id BY page LOOP
UPDATE opportunities SET sec_type = 'Unsec'
FROM opportunities AS opp
INNER JOIN accounts AS acc
ON opp.account_id = acc.id
WHERE acc.borrower = true
AND opp.sec_type IS NULL
AND opp.id >= j AND opp.id < j+page;
COMMIT;
END LOOP;
END; $$;
Second:
DO $$
DECLARE
page int := 10000;
min_id bigint; max_id bigint;
BEGIN
SELECT max(id),min(id) INTO max_id,min_id FROM opportunities;
FOR j IN min_id..max_id BY page LOOP
UPDATE opportunities AS opp
SET sec_type = 'Unsec'
FROM accounts AS acc
WHERE opp.account_id = acc.id
AND opp.sec_type IS NULL
AND acc.borrower = true
AND opp.id >= j AND opp.id < j+page;
COMMIT;
END LOOP;
END; $$;
WORKS PERFECT!!!
POSTGRE SQL - UPDATE With a JOIN
BELOW CODE - Check the positioning of columns and IDs as below:
If you place it exactly as below, then only it will work!
---IF you want to update FIRST table
UPDATE table1
SET attribute1 = table2.attribute1
FROM table2
WHERE table2.product_ID = table1.product_ID;
OR
---IF you want to update SECOND table
UPDATE table2
SET attribute1 = table1.attribute1
FROM table1
WHERE table1.product_ID = table2.product_ID;

Doing an Update Ignore in SQL Server 2005

I have a table where I wish to update some of the rows. All the fields are not null. I'm doing a sub-query, and I wish to update the table with the non-Null results.
See Below for my final answer:
In MySQL, I solve this problem by doing an UPDATE IGNORE. How do I make this work in SQL Server 2005? The sub-query uses a four-table Join to find the data to insert if it exists. The Update is being run against a table that could have 90,000+ records, so I need a solution that uses SQL, rather than having the Java program that's querying the database retrieve the results and then update those fields where we've got non-Null values.
Update: My query:
UPDATE #SearchResults SET geneSymbol = (
SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC)
WHERE isSNV = 0
If I add "AND symbol.name IS NOT NULL" to either WHERE I get a SQL error. If I run it as is I get "adding null to a non-null column" errors. :-(
Thank you all, I ended up finding this:
UPDATE #SearchResults SET geneSymbol =
ISNULL ((SELECT TOP 1 symbol.name FROM
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE joiner.indelID = #SearchResults.id ORDER BY symbol.id ASC), ' ')
WHERE isSNV = 0
While it would be better not to do anything in the null case (so I'm going to try to understand the other answers, and see if they're faster) setting the null cases to a blank answer also works, and that's what this does.
Note: Wrapping the ISNULL (...) with () leads to really obscure (and wrong) errors.
with UpdatedGenesDS (
select joiner.indelID, name, row_number() over (order by symbol.id asc) seq
from
GeneSymbol AS symbol JOIN GeneConnector AS geneJoin
ON symbol.id = geneJoin.geneSymbolID
JOIN Result AS sSeq ON geneJoin.sSeqID = sSeq.id
JOIN IndelConnector AS joiner ON joiner.sSeqID = sSeq.id
WHERE name is not null ORDER BY symbol.id ASC
)
update Genes
set geneSymbol = upd.name
from #SearchResults a
inner join UpdateGenesDs upd on a.id = b.intelID
where upd.seq =1 and isSNV = 0
this handles the null completely as all are filtered out by the where predicate (can also be filtered by join predicate if You wish. Is it what You are looking for?
Here's another option, where only those rows in #SearchResults that are succesfully joined will be udpated. If there are no null values in the underlying data, then the inner joins will pull in no null values, and you won't have to worry about filtering them out.
UPDATE #SearchResults
set geneSymbol = symbol.name
from #SearchResults sr
inner join IndelConnector AS joiner
on joiner.indelID = sr.id
inner join Result AS sSeq
on sSeq.id = joiner.sSeqID
inner join GeneConnector AS geneJoin
on geneJoin.sSeqID = sSeq.id
-- Get "lowest" (i.e. first if listed alphabetically) value of name for each id
inner join (select id, min(name) name
from GeneSymbol
group by id) symbol
on symbol.id = geneJoin.geneSymbolID
where isSNV = 0 -- Which table is this value from?
(There might be some syntax problems, without tables I can't debug it)