Oracle update using subquery - sql

I need to convert my update Ms SQL Server query for Oracle
I have two tables:
Table1(id int, SaveId int, ChangeId int)
Table2(id int, smSaved int, boldId int)
The query is:
UPDATE
Table1
Set
SaveId=tbl.smSaved
FROM
Table1 tbl1
join Table2 tbl on tbl1.ChangeId=tbl.boldId
In MsSql everything works fine, but when I'm trying to run it in Oracle thats doesn't works. I can't figure out whats wrong with it.
Can anybody explain me what I need to change?

Try this:
UPDATE table1 SET SaveId =
(SELECT tbl.saved FROM table2 tbl
WHERE tbl.boldId = table1.ChangeId)
WHERE EXISTS(
SELECT tbl.saved FROM table2 tbl
WHERE tbl.boldId = table1.ChangeId
)
The first part of query update SaveId with value of tbl.saved (I suppose you have only one row of table2 linked with table1.
The second part (exists) guarantee you have a correspond between two table (if you add exists you put NULL where not exists row in table2)

You are may to use update with subquery same MS SQL. In Oracle its look like:
UPDATE (SELECT t1.savedId t1_saved
, t2.smsaved t2_saved
FROM table1 t1
, table2 t2
WHERE t1.changeid = t2.boldid)
SET t1_saved = t2_saved

Related

How to Get matching records using Exists statement along with a condition on the main table

I have a problem regarding sql 'exists' statement and I will highly appreciate any kind of help.
Let me explain you what I need to accomplish.
I have two tables where I would like to get matching records from table1 which also exits in table2. Till this, it is simple. However, I also want to get those records from table1 along with matching records which has a particular column NULL in Table1. In other words I need to get those records from Table1 either they exist in Table2 or they have a specific column NULL. I wrote the following query to accomplish this.
CREATE TABLE #Table1(ID INT, Column2 INT NULL)
CREATE TABLE #Table2(ID INT)
INSERT INTO #Table1 VALUES(1, NULL)
INSERT INTO #Table2 VALUES(2)
select * from #Table1
WHERE EXISTS (SELECT NULL from #Table2 where #Table2.ID = #Table1.ID OR #Table1.Column2 IS NULL)
DROP TABLE #Table1;
DROP TABLE #Table2;
This query works when Table2 is not empty. However, if Table2 is empty then IS NULL condition does not work.
In order to resolve this I also tried adding a dummy record in case Table2 is empty by adding a union, but it does not resolve my problem either because there will always a record when I should get 0 records.
Like this
select * from #Table1
WHERE EXISTS (SELECT ID WHERE NOT EXISTS (SELECT * FROM #Table2)
UNION
SELECT NULL from #Table2 where #Table2.ID = #Table1.ID OR #Table1.Column2 IS NULL)
Note: I know this can be solved using joins but I would like to solve it using Exists statement because this is the part of a large system which simply cannot be converted to joins. I have given the above as a simple scenario.
Any kind of help would be highly appreciated.
Will this work?
WHERE EXISTS (SELECT 1 from #Table2 where #Table2.ID = #Table1.ID) OR #Table1.Column2 IS NULL
Move the condition outside the EXISTS. It is closer to how you describe the problem anyway:
select t1.*
from #Table1 t1.
WHERE t1.Column2 IS NULL OR
EXISTS (SELECT 1 from #Table2 t2 where t2.ID = t1.ID);
Notes:
Although EXISTS (SELECT NULL . . . ) is allowed an works, I find it highly misleading. In practice, NULL often represents missing values so the result is a bit of cognitive dissonance. Besides, SELECT 1 is easier to type.
I recommend table aliases; they make the query easier to write and to read.

SQL update statement with different table in from clause

Out of accident I noticed that the following query is actually valid:
UPDATE bikes
SET price = NULL
FROM inserted
WHERE inserted.owner_id = 123456
This is part of a trigger where someone forgot to join the original table to the inserted table. The result is that when the trigger is executed, all prices are set to NULL.
The correct SQL statement is this:
UPDATE bikes
SET price = NULL
FROM inserted
INNER JOIN bikes ON bikes.id=inserted.id
WHERE inserted.owner_id = 123456
How/why is this first statement valid?
Why wouldn't it be valid? SQL Server doesn't know what you're trying to do. It thinks you want to update all of the fields where some condition exists on another table. See the last update below.
SETUP
declare #table table
(
id int,
name varchar(10)
)
declare #itable table
(
id int,
name varchar(10)
)
insert into #table (id, name)
select 1,'abc' union
select 2,'def' union
select 3,'ghi' union
select 4,'jkl' union
select 5,'mno' union
select 6,'pqr'
insert into #itable (id, name)
select 1,'abc' union
select 2,'def' union
select 3,'ghi' union
select 4,'jkl' union
select 5,'mno' union
select 6,'pqr'
All names on #table will change to zzz
update #table
set name = 'zzz'
from #itable i
where i.id = 1
select * from #itable
select * from #table
All names where id = 1 on #table becomes yyy
update #table
set name = 'yyy'
from #itable i
inner join #table t on i.id = t.id
where i.id = 1
select * from #itable
select * from #table
This will NOT update anything
update #table
set name = 'aaa'
from #itable i
where i.id = 133
select * from #itable
select * from #table
The first statement does not work as expected because it is missing the entire INNER JOIN line with the bikes and inserted table. Without that SQL Server will update all rows as all rows will qualify for an update when the inserted.owner_id = 123456.
You can reproduce this outside of the trigger in TSQL like :
update bikes set price =null
from SomeOtherTable
where SomeOtherTable.SomeColumn = 'some_value_that_exists'
This is syntactically valid statement in SQL Server. If the Intention is to update bikes table based on existance of a row in some unrelated table that cant be joined because the 2 tables arent related then this is how you would do it. But that is not your requirement. Hence why it updates all records instead of only those that match the bikes.id In programming terms this is called as a logical bug.
The inner join makes it more restrictive and forces to to update only those rows that match the join condition between the 2 tables (bikes.id=inserted.id comparison )
In Simple terms the from clause is optional..Consider below query..
update table
set id=10
This has one table right after update clause ,sql just updates it..
now consider below query..
update table1
set id=40
from table2..
What do you think SQL does,it updates all the rows same as first query..
unless you refer to another table in from clause and join like below
update t1
set t1.id=40
from
table1 t1
join
table2 t2
on t1.id=t2.id
below is the from clause explanation in update syntax stripped down to show only to relevant parts..
If the object being updated is the same as the object in the FROM clause and there is only one reference to the object in the FROM clause, an object alias may or may not be specified. If the object being updated appears more than one time in the FROM clause, one, and only one, reference to the object must not specify a table alias. All other references to the object in the FROM clause must include an object alias
As long as above rules are valid (as in your case),SQL will happily update table found immediately after update clause

update query for multiple rows with different where condition?

How to write update query in sql to update multiple rows with different where condition ?For example if i want to change the name of 100 rows of a particular table with different id's?
update table set name = 'value1' where id=1,
set name ='value2' where id=2;
But like this i can't write for 100 entries. . Any help?
You can create a temp table with these 100 entries then update the table by joining this new table, something like:
CREATE TABLE Temp(
Id int NOT NULL,
Name Varchar(50)
) ;
UPDATE YourTable t1
INNER JOIN Temp t2 ON t1.Id = t2.Id
SET t1.Name = t2.Name;

T-SQL For Each Alternative?

I need to take data from one table and import it into another table. In pseudocode, something like this:
For Each row in table1
If row.personid is in table2 then
update table2.row
Else
insert row into table2
End If
Next
What is the best way to do this in T-SQL? As I understand it T-SQL doesn't support For Each..Next, so what alternatives do I have?
If you're using SQL Server 2008 then you could use the MERGE statement. Maybe something like this:
MERGE table2 AS t -- target
USING table1 AS s -- source
ON ( t.personid = s.personid )
WHEN MATCHED THEN
UPDATE
SET second_column = s.second_column,
third_column = s.third_column,
etc = s.etc
WHEN NOT MATCHED THEN
INSERT ( personid, second_column, third_column, etc )
VALUES ( s.personid, s.second_column, s.third_column, s.etc )
All things being equal, set based operations are better.
update t1
set t1.x = t2.x
.
.
.
from table1 t1
inner join table2 t2 on t1.id = t2.t1id
then
insert into table1
select * from table2 t2 where t2.t1id not in (select table1.id from table1 )
You could use a cursor for this as others have described. Personally I like doing two statements in a row like so:
UPDATE tbl2 SET field1=tbl1.field1, field2=tbl1.field2 -- etc.
FROM tb12
JOIN tbl1 on tbl2.personid = tbl1.personid
INSERT tbl2 (personid, field1, field2)
SELECT personid, field1, field2
FROM tbl1
WHERE NOT EXISTS (select personid from tbl2 where personid = tbl1.persondid)
doing this in a while loop is just wrong.
for your situatuin you can use the new MERGE statement in sql server 2008.
Here's a simple example on how to do it.
If you're on SQL Server 2008 then the best way to do this is with the MERGE statement. Something like...
MERGE INTO target_table t
USING source_table s
ON t.personid = s.personid
WHEN MATCHED THEN
UPDATE ...
WHEN NOT MATCHED THEN
INSERT ...
You state TSQL but don't give a version. If you are on SQL2008 the Merge statement should do what you need.
One of the most common ways is to use cursors. That way you can go through each record that your query returns and handle it accordingly, either with an UPDATE or INSERT.
See: http://msdn.microsoft.com/en-us/library/ms180169.aspx

Avoid duplicates in INSERT INTO SELECT query in SQL Server

I have the following two tables:
Table1
----------
ID Name
1 A
2 B
3 C
Table2
----------
ID Name
1 Z
I need to insert data from Table1 to Table2. I can use the following syntax:
INSERT INTO Table2(Id, Name) SELECT Id, Name FROM Table1
However, in my case, duplicate IDs might exist in Table2 (in my case, it's just "1") and I don't want to copy that again as that would throw an error.
I can write something like this:
IF NOT EXISTS(SELECT 1 FROM Table2 WHERE Id=1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1
ELSE
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1 WHERE Table1.Id<>1
Is there a better way to do this without using IF - ELSE? I want to avoid two INSERT INTO-SELECT statements based on some condition.
Using NOT EXISTS:
INSERT INTO TABLE_2
(id, name)
SELECT t1.id,
t1.name
FROM TABLE_1 t1
WHERE NOT EXISTS(SELECT id
FROM TABLE_2 t2
WHERE t2.id = t1.id)
Using NOT IN:
INSERT INTO TABLE_2
(id, name)
SELECT t1.id,
t1.name
FROM TABLE_1 t1
WHERE t1.id NOT IN (SELECT id
FROM TABLE_2)
Using LEFT JOIN/IS NULL:
INSERT INTO TABLE_2
(id, name)
SELECT t1.id,
t1.name
FROM TABLE_1 t1
LEFT JOIN TABLE_2 t2 ON t2.id = t1.id
WHERE t2.id IS NULL
Of the three options, the LEFT JOIN/IS NULL is less efficient. See this link for more details.
In MySQL you can do this:
INSERT IGNORE INTO Table2(Id, Name) SELECT Id, Name FROM Table1
Does SQL Server have anything similar?
I just had a similar problem, the DISTINCT keyword works magic:
INSERT INTO Table2(Id, Name) SELECT DISTINCT Id, Name FROM Table1
I was facing the same problem recently...
Heres what worked for me in MS SQL server 2017...
The primary key should be set on ID in table 2...
The columns and column properties should be the same of course between both tables. This will work the first time you run the below script. The duplicate ID in table 1, will not insert...
If you run it the second time, you will get a
Violation of PRIMARY KEY constraint error
This is the code:
Insert into Table_2
Select distinct *
from Table_1
where table_1.ID >1
Using ignore Duplicates on the unique index as suggested by IanC here was my solution for a similar issue, creating the index with the Option WITH IGNORE_DUP_KEY
In backward compatible syntax
, WITH IGNORE_DUP_KEY is equivalent to WITH IGNORE_DUP_KEY = ON.
Ref.: index_option
From SQL Server you can set a Unique key index on the table for (Columns that needs to be unique)
A little off topic, but if you want to migrate the data to a new table, and the possible duplicates are in the original table, and the column possibly duplicated is not an id, a GROUP BY will do:
INSERT INTO TABLE_2
(name)
SELECT t1.name
FROM TABLE_1 t1
GROUP BY t1.name
In my case, I had duplicate IDs in the source table, so none of the proposals worked. I don't care about performance, it's just done once.
To solve this I took the records one by one with a cursor to ignore the duplicates.
So here's the code example:
DECLARE #c1 AS VARCHAR(12);
DECLARE #c2 AS VARCHAR(250);
DECLARE #c3 AS VARCHAR(250);
DECLARE MY_cursor CURSOR STATIC FOR
Select
c1,
c2,
c3
from T2
where ....;
OPEN MY_cursor
FETCH NEXT FROM MY_cursor INTO #c1, #c2, #c3
WHILE ##FETCH_STATUS = 0
BEGIN
if (select count(1)
from T1
where a1 = #c1
and a2 = #c2
) = 0
INSERT INTO T1
values (#c1, #c2, #c3)
FETCH NEXT FROM MY_cursor INTO #c1, #c2, #c3
END
CLOSE MY_cursor
DEALLOCATE MY_cursor
I used a MERGE query to fill a table without duplications.
The problem I had was a double key in the tables ( Code , Value ) ,
and the exists query was very slow
The MERGE executed very fast ( more then X100 )
examples for MERGE query
For one table it works perfectly when creating one unique index from multiple field. Then simple "INSERT IGNORE" will ignore duplicates if ALL of 7 fields (in this case) will have SAME values.
Select fields in PMA Structure View and click Unique, new combined index will be created.
A simple DELETE before the INSERT would suffice:
DELETE FROM Table2 WHERE Id = (SELECT Id FROM Table1)
INSERT INTO Table2 (Id, name) SELECT Id, name FROM Table1
Switching Table1 for Table2 depending on which table's Id and name pairing you want to preserve.