Merge / Update query to update - sql

I have two tables named CONTACT AND ROLES.
CONTACT TABLE LOOKS LIKE BELOW
CONTACT_ID
FIRST_NAME
LAST_NAME
PHONE
59285
AAA
BBB
99999
59281
AAA
BBB
99999
59288
ZZZ
YYY
11111
59282
ZZZ
YYY
11111
basically diff contact ids but same FIRST_NAME, LAST_NAME, PHONE
ROLES TABLE LOOKS LIKE
CONTACT_ID
59285
59281
59288
59282
I want to update the ROLES table, referencing the contact table to the minimum of the duplicate contact id so that the ROLES table looks like
CONTACT_ID
59281
59281
59282
59282
I am trying using merge
MERGE INTO ROLES T1 USING(
SELECT
MIN(CONTACT_ID) OVER (PARTITION BY FIRST_NAME, LAST_NAME, PHONE) AS min_contact_id
FROM CONTACT
) T2 ON (T1.ROWID = T2.ROWID) WHEN MATCHED THEN
UPDATE
SET T1.CONTACT_ID = T2.min_contact_id;
but it just gives output as 0 rows merged.

with cte as (
select distinct a.first_name,b.contact_id, a.min_id
from (
select first_name, min(contact_id) as min_id
from contact
group by contact_id) as a inner join contact b on a.first_name = b.first_name
)
update roles set roles.contact_id = cte.min_id
from cte inner join roles on roles.contact_id = cte.contact_id

You need to update your MERGE statement to a simple UPDATE statement -
UPDATE ROLES R
SET CONTACT_ID = (SELECT MIN_CONTACT_NO
FROM (SELECT CONTACT_ID, MIN(CONTACT_ID) OVER (PARTITION BY FIRST_NAME, LAST_NAME, PHONE) MIN_CONTACT_NO
FROM LOOKS) L
WHERE L.CONTACT_ID = R.CONTACT_ID);
As their ROWIDs never going to be same which was not correct in your query.
DB Fiddle.

Related

Update column value when their other column values are same

The Problem is, StudentId in row number 2 should be 1 because their Name and Father Name are the same. Similarly, StudentId in row number 4 should be 3 because Name and Father Name are the same
I have revised my query according to my requirement as I have to update my student_id when student_name, student dob, student father, email, countryId, and skype id will same now updated query will be
Merge into student_new_Backup
using ( select min(student_id) as stid, student_name, student_father,student_dob,email_id,skype_id,country
from student_new_Backup
group by student_name, student_father,student_dob,email_id,skype_id,country) a
on (student_new_Backup.student_name= a.student_name
and student_new_Backup.student_father=a.student_father
and student_new_Backup.student_dob=a.student_dob
unfortunately no student_id is update
and student_new_Backup.email_id=a.email_id
and student_new_Backup.skype_id=a.skype_id
and student_new_Backup.country=a.country)
when matched then
UPDATE SET student_new_Backup.student_id=a.stid
;
commit;
unfortunately, no student_id is an update
I think you want:
update t
set studentId = (select min(t2.studentId)
from t t2
where t2.name = t.name and t2.fathername = t.fathername
);
EDIT:
If you want NULL safe comparisons, then you need be be explicit:
update t
set studentId = (select min(t2.studentId)
from t t2
where (t2.name = t.name or t2.name is null and t.name is null) and
(t2.fathername = t.fathername or t2.fathername is null and t.fathername is null)
);
you can use merge for update
Merge into table_name
using ( select min(studentId) as stid, Name, fathername
from table_name
group by Name, fathername) a
on (table_name.Name= a.Name
and table_name.fatherName=a.fatherName)
when matched then
UPDATE SET table_name.studentId=a.stid
online demo

SQL query to copy the column value to another column after checking two conditions

I have a table customers, in which i have 6 attributes
CustomerID CustomerName CustomerCity CustomerState DuplicateCustIND
1 Richard Los Angeles New York
2 Jerome Houston Texas
3 Paul Los Angeles New York
In the above table, there are two duplicate column values CustomerCity and CustomerState are same for Richard and Paul. I would like to update the column DuplicateCustIND for paul with the customer id of Richard after checking the two similar column condition.
Till now I was using correlation query as
Update Customer C1 set C1.DuplicateCustIND = (select CustomerID from customers
where C3.CustomerCity =
C1.CustomerCity and
C3.CustomerState =
C1.CustomerState)
where exists(
Select 1 from Customers C2 where
C2.CustomerCity = C1.CustomerCity and
C2.CustomerState = C1.CustomerState and
C2.RowID<C1.RowID);
The above query didn't help me.
The below query could work.
merge INTO customers tgt USING
(SELECT a.id,
a.cname,
a.ccity,
a.cstate
FROM customers a,
(SELECT ccity,
cstate,
COUNT(*)
FROM customers b
GROUP BY ccity,
cstate
HAVING COUNT(*) > 1
) b
WHERE a.ccity = b.ccity
AND a.cstate = b.cstate
) src ON (tgt.id = src.id)
WHEN matched THEN
UPDATE SET tgt.dcustid = src.id;
You may probably rely on customerid and use a MERGE statement to update all records greater than that customerid with same city and state.
MERGE INTO customers t USING
( SELECT MIN(c1.CUSTOMERID) prim_id,
c2.CUSTOMERID sec_id
FROM Customers c1
JOIN customers c2 ON C2.CustomerCity = C1.CustomerCity
AND C2.CustomerState = C1.CustomerState
AND C2.CustomerID > C1.CustomerID
GROUP BY C1.CustomerCity,
C1.CustomerState,
c2.CUSTOMERID ) s ON (s.sec_id = t.CustomerID )
WHEN MATCHED THEN
UPDATE
SET t.DuplicateCustIND = s.prim_id;
SQLFiddle

Select duplicated field name

If I have the following scenario
Table that store people
id_person, name, age (...)
And a table that stores address of people
id_address, id_person, city
If I run a query like this
select * from people P left join address A on P.id_person = A.id_person
I'm getting id_person === null in result set (because there IS a person, but no address has been recorded it, which is fine).
The null is comming from the table address. Is it possible to solve this without doing select field1, field2, field3 ... (lots os fields)?
Example
Person
id_person Name
1 John
2 Steve
Address
id_address id_person city
1 1 'AnyCity'
When I run a query like this
select * from people P left join address A on P.id_person = A.id_person
where P.name = 'Steve'
His id_person is returning null
You mean you only want the id_person from the people table, not from the address table (which sometimes is NULL)?
select p.id_person, p.name, p.age, a.id_address, a.city
from people P left join address A ON P.id_person = A.id_person
Is it possible to solve this without doing select field1, field2, field3 ... (lots os fields)
No - you either use * or identify the fields. You could select all fields from one table and then cherry pick from the other table:
select P.*, A.address, A.City, ...
from people P
left join address A where P.id_person = A.id_person

SQL find records with duplicate email and date of birth

I'm trying to write a query to find any duplicate records in my database. I want to find all records (not the count) where the EmailAddress AND DateofBirth (both columns) already exist on another record.
Account tbl contains the EmailAddress.
User tbl contains the DateOfBirth
Join on AccountID
The following query selects records where the EmailAddress exists in another record OR the DateOfBirth exists in another record, but I'm unable to combine the two conditions. If I'm correct so far, the 'and' on line 7 acts more like an 'or' in my case..?
select a.AccountName, a.EmailAddress, u.DateOfBirth from Account as a
join [User] as u
on a.AccountID = u.AccountID
where a.EmailAddress in (
select EmailAddress from Account group by EmailAddress having count(*) > 1
)
and
DateOfBirth in(
select DateOfBirth from [User] group by DateOfBirth having count(*) > 1
)
order by u.DateOfBirth, a.EmailAddress
For example, this may produce 50 records. If I look through them, I find 5 records all with the matching EmailAddress, however only 4 of them have the same DateOfBirth. The 5th record is displaying due to another record in the database with the same DateOfBirth but different EmailAddress.
I'd like to find only those records who have both the matching email and dob.
Thanks as always, please ask if you require a further description.
Regards
Json
Using your approach, you can use exists:
select a.AccountName, a.EmailAddress, u.DateOfBirth
from Account as a join
[User] as u
on a.AccountID = u.AccountID
where exists (select EmailAddress
from Account a2 join
[User] u2
on a.AccountID = u.AccountID
where a2.EmailAddress = a.EmailAddress and
u2.DateOfBirth = u.DateOfBirth
group by EmailAddress
having count(*) > 1
)
order by u.DateOfBirth, a.EmailAddress;
A better way is to use window/analytic functions:
select AccountName, EmailAddress, DateOfBirth
from (select a.AccountName, a.EmailAddress, u.DateOfBirth,
count(*) over (partition by a.EmailAddress, u.DateOfBirth) as cnt
from Account as a join
[User] as u
on a.AccountID = u.AccountID
) ua
where cnt > 1
order by DateOfBirth, EmailAddress;
Join the two tables on the account id.
Group by email and date
Show only those entries which have count(*) > 1 (using the HAVING expression).
In MySQL (I have no MS SQL server available at the moment), this can be done with:
SELECT * FROM a JOIN b ON a.account = b.account
GROUP BY email, birth
HAVING count(*) > 1;
Where I used the following commands to setup the tables a and b:
create table a (
account int primary key auto_increment,
email text
);
create table b (
account int,
birth date,
constraint foreign key (account) references a (account)
);
insert into a (email) values ("email1"), ("email1"), ("email2"), ("email2");
insert into b values (1, "2000-01-01"), (2, "2000-01-01"), (3, "2000-01-01"), (4, "2000-01-02");

SQL Multiple Duplicate Row Detection

I'm trying to determine a correct way to isolate rows within a table that have the same values in 2 columns.
There are two tables, one (Name) with the person's names and IDs, and the other one (Nation) with people's IDs and their nations. I join the two tables with inner join, and now the new table columns consist of an ID, first name, last name, and nation. If I want to find pairs of people who have the same last name and are from the same nation, why isn't
select ID, FName, LName, Nation
from (Name inner join Nation on Name.ID = Nation.ID)
group by Name, Nation
having count(Name) > 1 and count(Nation) > 1
working?
I'm aiming for the result to be a table with columns:
ID -------First--------------- Last ---------Nation
where the last names and nations will be identical pairs while first names will be different.
I feel like the group by part isnt appropriate, but is there even an alternate way? Thanks for any help.
If you are using MS SQL Server:
select
*
from
(
select
Name.*,
Nation.Nation,
cnt = count(*) over(partition by LName, Nation)
from Name
join Nation on Nation.ID = Name.ID
) t
where cnt > 1
Try this:
SELECT * FROM (
SELECT Name.ID, Name.FName, Name.LName, Nation.Nation
FROM Name
INNER JOIN Nation ON (Name.ID = Nation.ID)
) a
INNER JOIN (
SELECT Name.ID, Name.FName, Name.LName, Nation.Nation
FROM Name
INNER JOIN Nation ON (Name.ID = Nation.ID)
) b ON (a.LName = b.LName AND a.Nation = b.Nation)
WHERE a.ID < b.ID
As Simon Righarts hinted, something's not right with the design.
Scenario 1)
If a name can have multiple nations, you would have 3 tables implementing an n:m relationship.
CREATE TABLE name (name_id int, name text, ...);
CREATE TABLE nation (nation_id int, nation text, ...);
CREATE TABLE nationality (name_id int references name(name_id)
,nation_id int references nation(nation_id)
... );
Query for the scenario:
SELECT a.name_id, a.fname, a.lname, n.nation
FROM name a
JOIN nationality na USING (name_id)
JOIN nation n USING (nation_id)
JOIN (
SELECT a.lname, na.nation_id
FROM name a
JOIN nationality na USING (name_id)
GROUP BY 1,2
HAVING count(*) > 1) x USING (lname, nation_id)
Scenario 2)
If a name can only have one nation, there would be a column nation_id in the table name:
CREATE TABLE name (name_id int
,name text
,nation_id int references nation(nation_id), ...);
CREATE TABLE nation (nation_id int, nation text, ...);
Query for this scenario:
SELECT a.name_id, a.fname, a.lname, n.nation
FROM name a
JOIN nation n USING (nation_id)
JOIN (
SELECT a.lname, a.nation_id
FROM name a
GROUP BY 1,2
HAVING count(*) > 1) x USING (lname, nation_id);
All multiple occurrences are included here, not just "pairs" - assuming you meant that.
Your actual description doesn't fit either scenario.