SQL update statement is updating - sql

I'm confounded by an Update statement that seems easy on the surface. I need to update the values in 4 columns in Table1 with values from Table2 based on matching two separate columns from each table. Here is the general syntax:
Update Table1
set field1 = [table2 field1]
, field2 = [table2 field2]
, field3 = [table2 field3]
, field4 = [table2 field4]
--select *
from Table2 p inner join Table1 c
on p.matchfield1 = c.matchfield1 and p.matchfield2 = c.matchfield2
where c.database_id = 1 --qualifier since join clause may not provide unique result set
and p.matchfield1 = 123456 --to test the statement on a single record first
When I run the clause as a select statement I get a single record as expected. However, when I run the update clause using the same 'from' language I find that the query updates EVERY row in Table1 with the values from Table2 where matchfield1 = 123456.
I'm wondering if I need to further clarify my where clause to qualify based on the matchfield2 value (eamil address in my example) so I'd add to the end of the statement 'and p.matchfield2 = 'email#address.com''.
I suspect I'm a very small tweak away from making this work but in the meantime it's making me half crazy. Thanks for any advice!

Instead of doing a JOIN on the same table, try this (assuming you are using SQL Server)...
UPDATE Table1
set field1 = [table2 field1]
, field2 = [table2 field2]
, field3 = [table2 field3]
, field4 = [table2 field4]
FROM Table2 p
WHERE database_id = 1
AND p.matchfield1 = 123456
AND p.matchfield1 = matchfield1 AND p.matchfield2 = matchfield2
You could also modify your query to tighten the filtering by adding AND c.matchfield1 = matchfield1 AND c.matchfield2 = matchfield2 to the WHERE clause.

Related

Conditional UPDATE for non-related tables in SQLServer 2008

I'm trying to update historicTable (8k records containing employee data) when 2 IDs match (one company id and the other area id) with the tempTable, which is a temporary table with the data I want to update (SUBG_ROT), else (the column stays empty), it should copy data from colx to coly from the same historic table. I was thinking of a JOIN/INNER JOIN but I can't get the structure at all, so I did a stored procedure with a conditional update, but I can't figure out how to call the temporary table. Any hints on the logic/code are appreciated, I'm starting on SQL Server so I'm kinda clueless.
In my mind the code should do:
Update historicTable set SUBG when h.id1 = t.id1 and h.id2 = t.id2 then h.SUBG = t.SUBG else h.id1 = h.SUBG
And this is the code
CREATE PROCEDURE updateHistoric
AS
UPDATE dbo.historicTable
SET SUBG_ROT = CASE
WHEN id1 = temptable.id1 AND id2 = temptable.id2
THEN SUBG_ROT = temptable.SUBG_ROT
ELSE SUBG_ROT = AREA
END
GO
You can try using OUTER APPLY like follownig.
UPDATE t
SET t.subg_rot = CASE
WHEN o.subg_rot IS NOT NULL THEN o.subg_rot
WHEN t.subg_rot IS null then t.area
ELSE t.subg_rot
END
FROM dbo.historictable t
OUTER APPLY (SELECT TOP 1 subg_rot
FROM temptable t2
WHERE t1.id1 = t2.id1
AND t1.id2 = t2.id2)o
Note: Same thing is also possible using LEFT JOIN or sub queries.

Run second query if first query does not return any results and return

I am trying to keep this to the minimal table queries to ensure less database usage. I am using Microsoft SQL Server Management Server.
I have a query which will sometimes return nothing depending on the user's current status. If this first query does not return any results, I would like the second query to run.
This is inside of a function and requires returning a single row of column data. I will include the queries with names changed for an example. I will do my own optimization after to make a temp table so the database is not accessed as often. I just need to figure out how to make this work first.
-- Query #1
INSERT #tlbReturn (returnInfo1, returnInfo2)
SELECT TOP(1) returnInfo1, returnInfo2
FROM table1 AS t1a
INNER JOIN table1 AS t1b ON t1a.someData1 = t1b.someData1
AND t1a.someData2 = t1b.someData2
AND t1a.someData3 = t1b.someData3
AND t1a.someData4 = t1b.someData4
INNER JOIN table2 AS t2 ON t2.someData6 = t1b.someData7
AND t2.someData8 = t1b.someData9
WHERE t1a.someData10 = 'value'
AND t1b.someData11 IN ('value1', 'value2')
ORDER BY t1b.someDate DESC;
-- Query #2
INSERT #tlbReturn (returnInfo1, returnInfo2)
SELECT TOP(1) returnInfo1, returnInfo2
FROM table1 AS t1a
INNER JOIN table1 AS t1b ON t1a.someData1 = t1b.someData1
AND t1a.someData5 = t1b.someData5
INNER JOIN table2 AS t2 ON t2.someData6 = t1b.someData7
AND t2.someData8 = t1b.someData9
WHERE t1a.someData10 = 'value'
AND t1b.someData11 IN ('value1', 'value2')
ORDER BY t1b.someDate DESC;
In theory I would like something like,
IF EXISTS(QUERY1) THEN RETURN
ELSE RETURN QUERY2
Check the value of ##ROWCOUNT after the first query.
Do a first select, check ##ROWCOUNT and if it's a zero do a second select

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.

SQL Query Joining Update and Select in a single statement

Need a SQL query to perform UPDATE and SELECT in a single statement.
I have two tables.
First I need to filter the second table
After filtering the second table, I need to update first table from the resultant filtered second table.
update statement followed by Select statement
You haven't told us what your database is, but this will work for SQL Server.
update FirstTable
set f.FirstName = case when f.FirstName = s.MiddleName then s.FN else f.FirstName end,
f.LastName = case when f.LastName = s.MiddleName then s.FN else f.LastName end
from FirstTable f
inner join SecondTable s on f.FirstName = s.MiddleName or f.LastName = s.MiddleName
where s.FN <> 'aaa' -- Missed first time
I don't think it will work exactly as laid out for other RDBMs'.
EDIT: Added the where to the SQL, and the explanation that follows:
The query is of the form:
update table1
set col1 = x.colN
from table1 t
inner join table2 x on some condition
This is in two parts the update + set lines, and the from query which is a complete select statement without the actual select column list. Think of the second as being prefixed by 'select *'.
The second part (the guts of a select statement) must use the same table as the update part - FirstTable in your problem and table1 in the skeleton above. Since it selects rows from the same table as the update it knows which rows you want to update, and makes the columns in the select part available to the update part. In the skeleton, I can then set col1 from table1 to colN from table2.
Your problem is a bit more complicated as I don't necessarily want to change FirstName or LastName. To take FirstName, I want to change FirstName to FN when FirstName = MiddleName. To do this I use a case as part of the set:
set f.FirstName = case when f.FirstName = s.MiddleName then s.FN else f.FirstName end
This says the when FirstName = MiddleName then set FirstName o FN, else set it to FirstName (in other words don't change it).
Repeat for LastName.
Hope that helps.

WHERE NOT EXISTS multiple conditions

How Do I set multiple AND conditions?
ex.
SELECT *
FROM CONFIRMED
WHERE NOT EXISTS
(
SELECT *
FROM Import_Orders
WHERE Import_Orders.Customer = CONFIRMED.Customer
AND Import_Orders.Reference = CONFIRMED.Reference
AND Import_Orders.[Index] = CONFIRMED.[Index]
AND Import_Orders.QuantityToDeliver = CONFIRMED.QuantityToDeliver
AND Import_Orders.DateToDeliver = CONFIRMED.DateToDeliver
);
I know this works on my tables with one WHERE & AND condition but not with several.
I Need a result of two tables where the above conditions do not match. I do not have identical keys in the two tables. Now with this code I get all the results that are in table CONFIRMED.
Here is the syntax for multiple tables:
WHERE NOT EXISTS (...) AND NOT EXISTS (...) AND NOT EXISTS (...)
However, if the database is so large that you care about performance, you'll need a much less obvious syntax along the following lines:
LEFT JOIN Some_Table t ON (t.xxx = Main_Table.xxx)
LEFT JOIN Another_Table t2 ON (t2.xxx = Main_Table.xxx)
LEFT JOIN Yet_Another_Table t3 ON (t3.xxx = Main_Table.xxx)
...
WHERE t.id IS NULL AND t2.id IS NULL AND t3.id IS NULL
For one table and one composed condition, like in the SQL sample in your question:
LEFT JOIN Some_Table t ON
t.xxx = Main_Table.xxx
AND t.yyy = Main_Table.yyy
AND t.zzz = Main_Table.zzz
WHERE t.id IS NULL
This is expected to return rows that exist in Main_Table but do not have matching rows in Some_Table, assuming the columns xxx, etc., are non-nullable.
If, for example, xxx is nullable, here is how you need to modify the query further:
LEFT JOIN Some_Table t ON
(t.xxx = Main_Table.xxx OR (t.xxx IS NULL AND Main_Table.xxx IS NULL))
AND t.yyy = Main_Table.yyy
AND t.zzz = Main_Table.zzz
WHERE t.id IS NULL
I am guessing that you have an ID on Import_Orders, if not use any field name that is turning up empty on the query. You would be better using field names rather than *. I have added an example for Import_Orders.
SELECT CONFIRMED.*, Import_Orders.ID, Import_Orders.Customer
FROM CONFIRMED
LEFT JOIN Import_Orders
ON Import_Orders.Customer = CONFIRMED.Customer
AND Import_Orders.Reference = CONFIRMED.Reference
AND Import_Orders.[Index] = CONFIRMED.[Index]
AND Import_Orders.QuantityToDeliver = CONFIRMED.QuantityToDeliver
AND Import_Orders.DateToDeliver = CONFIRMED.DateToDeliver
WHERE Import_Orders.ID Is Null
More information
Fundamental Microsoft Jet SQL for Access 2000
Intermediate Microsoft Jet SQL for Access 2000
Advanced Microsoft Jet SQL for Access 2000
You could just replace all the "=" with "<>" and you should get all the results that don't have a match on all criteria.
SELECT *
FROM CONFIRMED
WHERE EXISTS
(
SELECT *
FROM Import_Orders
WHERE Import_Orders.Customer <> CONFIRMED.Customer
AND Import_Orders.Reference <> CONFIRMED.Reference
AND Import_Orders.[Index] <> CONFIRMED.[Index]
AND Import_Orders.QuantityToDeliver <> CONFIRMED.QuantityToDeliver
AND Import_Orders.DateToDeliver <> CONFIRMED.DateToDeliver
);