Update table using like operator - sql

I have 2 tables
table 1
Diagnosis GroupID
155.0 - blaaaaaa GAS
table 2
Code GroupID
155.0
155.0
155.0
155.0
I did try to update GroupID of second table from first
update Table2 set GroupID= GroupID from table 1 where Diagnosis like '%'+Code+'%'
but its not working

Your current syntax for an update join is slightly off. Try using this instead:
UPDATE t2
SET GroupID = t1.GroupID
FROM Table2 t2
INNER JOIN Table1 t1
ON t1.Diagnosis LIKE '%' + t2.Code + '%'

You can use the following code:
UPDATE
Tb2 SET Tb2.GroupId = Tb1.GroupId
FROM table1 as Tb1 INNER JOIN table2 as Tb2
ON Tb1.Diagnosis LIKE '%'+Tb2.Code+'%';

This would help, http://rextester.com/NILBI39557
CREATE TABLE Table1
(
Diagnosis VARCHAR(255)
,GROUPID VARCHAR(255)
);
Insert Into Table1 Values('155.0 - blaaaaaa','GAS');
CREATE TABLE Table2
(
Code VARCHAR(255)
,GROUPID VARCHAR(255)
);
Insert Into Table2 VALUES ('155.0', NULL);
Insert Into Table2 VALUES ('155.0', NULL);
Insert Into Table2 VALUES ('155.0', NULL);
Insert Into Table2 VALUES ('155.0', NULL);
SELECT * FROM Table2;
UPDATE T2
SET T2.GroupId = T1.GroupId
FROM Table1 as T1 INNER JOIN Table2 as T2
ON T1.Diagnosis LIKE '%'+T2.Code+'%';
SELECT * FROM Table2;

Related

Get the list of name column values which are not common in both the tables?

recently i gave an interview where the question was
suppose there are two tables in database.
Table T1 has a column named "name" in it and few other columns
Table T2 also has a column name "name" and few other columns
suppose table T1 has values in name column as
[n1,n2,n3,n4,n5]
and values in the "name" column of table T2 are
[n2,n4]
then output should be
[n1,n3,n5] as n2 and n4 are common in both tables
we needs to find the list of names which are not common in both the tables.
The solution that i provided him was using join in the below form
select name from table1 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
UNION
select name from table2 where name not in (select t1.name from table1 t1 join table2 t2 on t1.name=t2.name)
But he said there is still a better solution. I was not able to come up with any different and more efficient solution. What is the other efficient way to get the list of names if there is any?
If the NAME column does not have NULL values, there is also
select distinct(coalesce(a.name, b.name)) name
from table1 a
full join table1 b on a.name = b.name
where a.name is null or b.name is null
(Corrected WHERE condition, sorry...)
Use FULL OUTER JOIN:
SELECT DISTINCT(COALESCE(t1.NAME, t2.NAME)) AS NAME
FROM TABLE1 t1
FULL OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL OR
t2.NAME IS NULL
A FULL OUTER JOIN is similar to a LEFT OUTER JOIN unioned with a RIGHT OUTER JOIN - it returns rows where data exists in the first table but not the second, or where it data exists in the second table but not the first. You could get the same effect by using
SELECT t1.NAME
FROM TABLE1 t1
LEFT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t2.NAME IS NULL
UNION
SELECT t2.NAME
FROM TABLE1 t1
RIGHT OUTER JOIN TABLE2 t2
ON t2.NAME = t1.NAME
WHERE t1.NAME IS NULL
and in fact the above is what you'd need to do if you were using a database which doesn't support the FULL OUTER JOIN syntax (e.g. MySQL, the last time I looked).
See this dbfiddle
Union the tables and return the values that don't have a count of 2:
create table t1 (
c1 int
);
create table t2 (
c1 int
);
insert into t1 values ( 1 );
insert into t1 values ( 3 );
insert into t2 values ( 2 );
insert into t2 values ( 3 );
commit;
select c1 only_in_one_table
from (
select 'T1' t, c1 from t1
union
select 'T2' t, c1 from t2
)
group by c1
having count(*) <> 2;
ONLY_IN_ONE_TABLE
1
2
I'm not a fan of not in with subqueries, because it behaves unexpectedly with null values. And the person asking would have to explain what "better" means. Your version is actually reasonable.
I might be inclined to approach this using aggregation:
select name
from ((select distinct name, 1 as in_table1, 0 as in_table2
from table1
) union all
(select distinct name, 0 as in_table1, 0\1 as in_table2
from table2
)
) t
group by name
having max(in_table1) <> max(in_table2);
In a real world case, you would probably have a separate table with all names. If so:
select n.*
from names n
where (not exists (select 1 from table1 t1 where t1.name = n.name) and
exists (select 1 from table2 t2 where t2.name = n.name
) or
(exists (select 1 from table1 t1 where t1.name = n.name) and
not exists (select 1 from table2 t2 where t2.name = n.name
);
This is usually the fastest approach because it does not involve any aggregation or duplicate removal.
If you want to use SET operator then find the solution as below:
CREATE TABLE TABLE1(NAME VARCHAR2(100));
CREATE TABLE TABLE2(NAME VARCHAR2(100));
INSERT INTO TABLE1 VALUES('A');
INSERT INTO TABLE1 VALUES('B');
INSERT INTO TABLE1 VALUES('C');
INSERT INTO TABLE2 VALUES('A');
INSERT INTO TABLE2 VALUES('B');
INSERT INTO TABLE2 VALUES('D');
SELECT
NAME
FROM
(
SELECT
NAME
FROM
TABLE1
UNION
SELECT
NAME
FROM
TABLE2
)
WHERE
NAME NOT IN (
SELECT
NAME
FROM
TABLE1
JOIN TABLE2 USING ( NAME )
);
Cheers!!
Yet another possible solution:
Find those that are in the first table but not in the second table using the MINUS operator (which is Oracle's implementation of the standard EXCEPT). Then UNION that with those that are in the second but not in the first.
(
select name
from t1
minus
select name
from t2
)
union all
(
select name
from t2
minus
select name
from t1
);
Given this setup:
create table t1
(
name varchar(10)
);
insert into t1 values ('Arthur');
insert into t1 values ('Zaphod');
create table t2
(
name varchar(10)
);
insert into t2 values ('Tricia');
insert into t2 values ('Zaphod');
This returns:
NAME
------
Arthur
Tricia
select id from((select id from table1)
union all
(select id from table2)) as t1
group by id having count(id)=1
Using the basic set operations the following query should work.
(
select name from table1
union all
select name from table2
)
minus
(
select name from table1
intersect
select name from table2
)
;
Regards
Akash

Delete duplicates, and reassign FK value in SQL

I have two tables:
Table1:
[id], [ColA]
Table2:
[id], [Table1Id]
A previous update caused duplicates in Table1 and those duplicates to be assocated with rows in Table2. It looks like this in the db:
Table1
1, 89
2, 89
Table2
6, 1
7, 2
I would like to delete the duplicates and reassign the value of the Table2.Table1Id to the one Table1.id row that should be left. Is this possible in a single statement? Ive seen this post on how to delete all but one, but I am lost on how to reassign the Table2.Table1Id value.
edit:
The end result should look like this:
Table1
2, 89
Table2
6, 2
7, 2
drop table if exists dbo.Table2;
drop table if exists dbo.Table1;
create table dbo.Table1 (
ID int primary key
, ColA int
);
create table dbo.Table2 (
ID int
, Table1ID int
);
alter table dbo.Table2
add constraint FK_Table2_Table1
foreign key (Table1ID)
references dbo.Table1 (ID);
insert into dbo.Table1 (ID, ColA)
values (1, 89), (2, 89);
insert into dbo.Table2 (ID, Table1ID)
values (6, 1), (7, 2);
drop table if exists #temp;
select
ttt.ID
into #temp
from (
select
t.ID
, t.ColA
, ROW_NUMBER() over (order by t.ID) as Rbr
from dbo.Table1 t
inner join (
select
t.ColA
from dbo.Table1 t
group by t.ColA
having COUNT (t.ID) > 1
) tt on t.ColA = tt.ColA
) ttt
where ttt.Rbr > 1
update t2
set
Table1ID = t1i.ID
from #temp t
inner join dbo.Table2 t2 on t.ID = t2.Table1ID
inner join dbo.Table1 t1 on t.ID = t1.ID
inner join dbo.Table1 t1i on t1.ColA = t1i.ColA
and t1i.ID not in (select t.ID from #temp t)
delete t1
from #temp t
inner join dbo.Table1 t1 on t.ID = t1.ID
select
*
from dbo.Table1 t
select
*
from dbo.Table2 t

Update and insert to one table from another

I have two tables:
table1: (ID, Code, Name)
table2: (ID, Code, Name)
with same columns
I want to to insert data from table1 to table2 or update columns if that exists in table2 (table1.ID = table2.ID)
What is the simple way to do this?
WITH OUT MERGE
Merge table2 as target
using table1 as source
on
target.id=source.id
When matched
Then
update
set target.id=source.id,
target.name=source.name
When not matched by Target Then
INSERT (id, name) VALUES (id, name);
There are some issues with Merge statement,so it should be used with caution..
Further i recommend ,using merge as two seperate DML statements like below..
insert into table2
select * from table1 t1 where not exists (select 1 from table2 t2 where t2.id=t1.id)
update t2
set
t2.id=t1.id,
t2.name=t1.name
from
table1 t1
join
table2 t2
on t1.id=t2.id
Reasons being stated by Paul White here in his detailed answer..
MERGE table2 t2
USING table1 t1
ON t1.ID = t2.ID
WHEN MATCHED THEN
UPDATE
SET t2.Code = t1.Code, t2.Name = t1.Name
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, Name, Code)
VALUES (t1.ID, t1.Name, t1.Code);
Assuming the ID column is unique and should not be set, it seems you could do it in two SQL Statements.
/* UPDATE the rows in TABLE2 */
UPDATE TABLE2
SET NAME = (SELECT NAME FROM TABLE1 WHERE TABLE1.CODE = TABLE2.CODE)
WHERE CODE IN (SELECT CODE FROM TABLE1)
/* INSERT the rows that are missing */
INSERT INTO TABLE2
(CODE, NAME)
(
SELECT CODE, NAME
FROM TABLE1
WHERE CODE NOT IN (SELECT CODE FROM TABLE2)
)
get all rows that are in table1 but not in table2
insert into table2(id, code, name)(
SELECT table1.*
FROM table1
LEFT JOIN table2 ON (table1.id = table2.id)
WHERE table2.C IS NULL
)
update table2
update table2 set name = (select name from table1 where table1.code = table2.code and table1.id = table2.id)
It might be worth looking at triggers on update and insert if you'd like to have this done manually
Inserting Date into target table once date is updated in source table
Here there is a working example:
create table Table1(id int,name varchar(100));
create table Table2(id int,name varchar(100));
create trigger Table1Trigger after insert on Table1 for each row begin
insert into Table2(id, name) values (new.id, new.name);
end;
Use the following queries to validate the results
insert into Table1 values(1,'John'),(2,'Smith'),(3,'Carol');
Here I am writing a script that use full when you want to update table2 from table1.
Update table2 set table2.code = table1.code, table2.name=table1.name from table1 where table2.id=table1.id
And if you want to insert then use this script.
Insert into table2 (id,code,name) select id,code,name from table1
If in table2 id is not auto increment.
Otherwise not insert the value of id column in table2.

How can i make an insert of a SCOPE_IDENTITY() into update in SQL SERVER

I want to insert an id that i created into an update of each row:
UPDATE TABLE1
SET NAME=(INSERT INTO TABLE2(EVT01,EVT02) values(0,0)
SELECT #id=SCOPE_IDENTITY() )
FROM TABLE1
INNER JOIN TABLE2 ON ......
How can i make that in SQL Server?
Thanks.
You can create an Insert Trigger on Table2 to Update Table1 using Inserted table:
CREATE TRIGGER [dbo].[YourTriggerName]
ON [dbo].[Table2]
AFTER INSERT
AS
BEGIN
UPDATE t1
SET NAME= t2.IdColName
FROM Table1 t1
INNER JOIN Inserted t2 ON ......
END
Declare #NewId Int
INSERT INTO TABLE2(EVT01,EVT02) values(0,0)
Select #NewId = ##Identity
UPDATE t1
SET t1.NAME = t2.Name
FROM TABLE1 As t1
Join TABLE2 As t2 On t1.somecolumn = t2.Id
Where t2.Id = #NewId
Edit:-
----- Table SourceTable
Insert Into TABLE2(EVT01,EVT02)
Select Col1
,Col2
From SrouceTable
Update t1
Set t1.Name = t2.Id
From TABLE1 As t1
Join TABLE2 As t2 On t1.Somecolumn = t2.Id
Join SourceTable As st On t2.EVT01 = Col1 ----Assumed there would be unique matching column

How to left join to first row in SQL Server

How to left join two tables, selecting from second table only the first row?
My question is a follow up of:
SQL Server: How to Join to first row
I used the query suggested in that thread.
CREATE TABLE table1(
id INT NOT NULL
);
INSERT INTO table1(id) VALUES (1);
INSERT INTO table1(id) VALUES (2);
INSERT INTO table1(id) VALUES (3);
GO
CREATE TABLE table2(
id INT NOT NULL
, category VARCHAR(1)
);
INSERT INTO table2(id,category) VALUES (1,'A');
INSERT INTO table2(id,category) VALUES (1,'B');
INSERT INTO table2(id,category) VALUES (1,'C');
INSERT INTO table2(id,category) VALUES (3,'X');
INSERT INTO table2(id,category) VALUES (3,'Y');
GO
------------------
SELECT
table1.*
,FirstMatch.category
FROM table1
CROSS APPLY (
SELECT TOP 1
table2.id
,table2.category
FROM table2
WHERE table1.id = table2.id
ORDER BY id
)
AS FirstMatch
However, with this query, I get inner join results. I want to get left join results. The tabel1.id in desired results should have '2' with NULL. How to do it?
use row_number and left join
with cte as(
select id,
category,
row_number() over(partition by id order by category) rn
from table2
)
select t.id, cte.category
from table1 t
left outer join cte
on t.id=cte.id and cte.rn=1
OUTPUT:
id category
1 A
2 (null)
3 X
SQLFIDDLE DEMO
select table1.id,
(SELECT TOP 1 category FROM table2 WHERE table2.id=table1.id ORDER BY category ASC) AS category
FROM table1
SELECT table1.id ,table2.category
FROM table1 Left join table2
on table1.id = table2.id
where table2.category = ( select top 1 category from table2 t where table1.id = t.id)
OR table2.category is NULL
Following the comment of t-clausen.dk this does the job:
change CROSS APPLY to OUTER APPLY