Changing record values based on whether there are duplicates when two tables are combined - sql

I know I can join Table #1 and Table #2 with a UNION and then filter out duplicate Id's using DISTINCT. However, for the duplicate contacts I'd like to change DrinkPreference to Coke/Pepsi.
Is this possible?
Starting Table #1
Id
FirstName
LastName
DrinkPreference
123
Tom
Bannon
Pepsi
124
Sarah
Smith
Pepsi
Starting Table #2
id
FirstName
LastName
DrinkPreference
125
Jim
Henry
Coke
123
Tom
Bannon
Coke
Table? #3 - combined with DrinkPreference set to Coke/Pepsi where contact exists in both tables?
Id
FirstName
LastName
DrinkPreference
125
Jim
Henry
Coke
123
Tom
Bannon
Coke/Pepsi
124
Sarah
Smith
Pepsi

You can try this one
SELECT coalesce(t1.firstname, t2.firstname) AS firstname,coalesce(t1.lastname,t2.lastname) AS lastname, CASE WHEN t1.drinkpreferences IS NULL THEN t2.drinkpreferences WHEN t2.drinkpreferences IS NULL THEN t1.drinkpreferences
ELSE t1.drinkpreferences || '/' || t2.drinkpreferences END AS drinkpreferences FROM table1 t1 FULL JOIN table2 t2 ON t1.id = t2.id

Achievable using multiple unions and joins.
select distinct FirstName, LastName, case when ct = 2 then 'Coke/Pepsi' else DrinkPreference end
from (
select FirstName, LastName, DrinkPreference, Id from table1
union all
select FirstName, LastName, DrinkPreference, Id from table2) a
left join
(
select count(1)ct, Id from
(select Id from table1
union all
select Id from table2) t1
group by Id
) b on b.Id = a.Id

Related

SQL UNION but fill in NULL value

I have two tables and a section of Table1 looks something like this
EmployeeID
FirstName
LastName
Gender
Age
A100
Bob
Odenkirk
Male
30
A101
Jon
Jones
NULL
36
Table2 looks similar but contains a duplicate entry with some varying amount of missing/available information, i.e.,
EmployeeID
FirstName
LastName
Gender
Age
A101
Jon
Jones
Male
NULL
A103
Angelina
Jolie
Female
40
I'm fairly new to SQL and I initially tried
SELECT *
FROM Table1
UNION
SELECT *
FROM Table2
But obviously, the A101 row has different NULL values so it doesn't get treated as duplicates and I get:
EmployeeID
FirstName
LastName
Gender
Age
A100
Bob
Odenkirk
Male
30
A101
Jon
Jones
NULL
36
A101
Jon
Jones
Male
NULL
A103
Angelina
Jolie
Female
40
Is there a general way (i.e. if the table is large and not sure which values might be missing from Table1 or Table2) to somehow "fill in" the NULL values and get the following target output:
EmployeeID
FirstName
LastName
Gender
Age
A100
Bob
Odenkirk
Male
36
A101
Jon
Jones
Male
30
A103
Angelina
Jolie
Female
40
Assuming you can never have "competing" values (i.e., both tables either have the same value or one of them has a null), you could union all the two queries, and then group by the EmployeeID and use max to get the present values and ignore nulls:
SELECT EmployeeID, MAX(FirstName), MAX(LastName), MAX(Gender), MAX(Age)
FROM (SELECT EmployeeID, FirstName, LastName, Gender, Age
FROM Table1
UNION ALL
SELECT EmployeeID, FirstName, LastName, Gender, Age
FROM Table2) T
GROUP BY EmployeeID
You could try to use FULL OUTER JOIN and COALESCE function
SELECT COALESCE(t1.EmployeeID, t2.EmployeeID),
COALESCE(t1.FirstName, t2.FirstName) AS FirstName,
COALESCE(t1.LastName, t2.LastName) AS LastName,
COALESCE(t1.Gender, t2.Gender) AS Gender,
COALESCE(t1.Age, t2.Age) AS Age,
FROM Table1 t1 FULL OUTER JOIN Table2 t2 ON t1.EmployeeID = t2.EmployeeID
If your DBMS does not support FULL OUTER JOIN, you could try to use UNION and COALESE function.
-- Retrieve all employees in Table1, then fill in NULL value using COALESCE function if it's exists in Table2
SELECT t1.EmployeeID,
COALESCE(t1.FirstName, t2.FirstName) AS FirstName,
COALESCE(t1.LastName, t2.LastName) AS LastName,
COALESCE(t1.Gender, t2.Gender) AS Gender,
COALESCE(t1.Age, t2.Age) AS Age,
FROM Table1 t1 LEFT JOIN Table2 t2 ON t1.EmployeeID = t2.EmployeeID
UNION ALL
-- Retrieve the rest employees, which is existed in Table 2, but is not existed in Table1
SELECT *
FROM Table2 t2
WHERE NOT EXISTS
(SELECT 1
FROM Table1 t1
WHERE t1.EmployeeID = t2.EmployeeID)

Getting records from 2 tables with common an uncommon columns

Below is similar example of the issue I have:
if I have this table 1:
Patient ID
Name
Check in Date
order name
preformed by
1
Jack
12/sep/2002
xray
Dr.Amal
2
Nora
15/oct/2002
ultrasound
Dr.Goerge
1
Jack
13/nov/2003
Medicine
Dr.Fred
table 2:
Patient ID
Name
Check in Date
order name
1
Jack
14/Jun/2002
xray 2
2
Nora
15/oct/2002
ultrasound
1
Jack
13/nov/2003
Medicine
3
Rafael
13/nov/2003
Vaccine
The result I need is as the following:
Name
Check in Date
order name
preformed by
Jack
12/sep/2002
xray
Dr.Amal
Nora
15/oct/2002
ultrasound
Dr.Goerge
Jack
13/nov/2003
Medicine
Dr.Fred
Jack
14/Jun/2002
xray 2
Null
Rafael
13/nov/2003
Vaccine
Null
If you noticed the result I need is all records of table 1 and all records of table 2 with no duplication and joining the same common fields and adding 'Preformed by' column from Table 1. I tried using 'UNION' as the following:
SELECT Name, Check_in_Date, order_name,preformed_by
FROM table1
UNION
SELECT Name, Check_in_Date, order_name,''
FROM table2
the result I get is 2 records for each patient with the same date one with preformed by one with null as the following:
Name
Check in Date
order name
preformed by
Jack
12/sep/2002
xray
Dr.Amal
Nora
15/oct/2002
ultrasound
Dr.Goerge
Nora
15/oct/2002
ultrasound
Null
Jack
13/nov/2003
Medicine
Dr.Fred
Jack
13/nov/2003
Medicine
null
Jack
14/Jun/2002
xray 2
Null
Rafael
13/nov/2003
Vaccine
Null
If the same ID has same check in date in both table it must return the preformed by of table 1 not null How can I do this?
Thank you.
What you need is a FULL JOIN matching by those three columns along with NVL() function in order to bring the values
from table2 which return null from table1 such as
SELECT NVL(t1.name,t2.name) AS name,
NVL(t1.check_in_date,t2.check_in_date) AS check_in_date,
NVL(t1.order_name,t2.order_name) AS order_name,
t1.preformed_by
FROM table1 t1
FULL JOIN table2 t2
ON t1.name = t2.name
AND t1.check_in_date = t2.check_in_date
AND t1.order_name = t2.order_name
or another method uses UNION to filter out duplicates and then applies an OUTER JOIN such as
SELECT tt.name, tt.check_in_date, tt.order_name, t1.preformed_by
FROM (
SELECT name, check_in_date, order_name FROM table1 UNION
SELECT name, check_in_date, order_name FROM table2
) tt
LEFT JOIN table1 t1
ON t1.name = tt.name
AND t1.check_in_date = tt.check_in_date
AND t1.order_name = tt.order_name
Demo

Best way to get distinct rows from a database

I have two tables tbPerson and tbComment with data such as below:
tbPerson
PersonID FirstName LastName
1 William Tell
2 Joe Smith
3 Sam Hampton
tbComment
CommentID PersonID CommentValue CommentPosition
45 2 This is my comment 100
46 2 This is my second comment 100
47 2 This is my third comment 100
48 1 A comment 101
49 3 This comment rules 102
50 3 A comment here 102
I need a query that only returns:
William Tell 101
Joe Smith 100
Sam Hampton 102
I figured it was something like below but this returns multiple rows. I only want the three rows.
SELECT FirstName, LastName, CommentPosition
FROM tbPerson
JOIN tbComment ON tbPerson.PersonID = tbComment.PersonID
GROUP BY FirstName, LastName, CommentPosition
For your data, your query should return only three rows. If you have multiple comments for a person, You need to choose which comment position you want.
The following would return the minimal value:
SELECT FirstName, LastName, MIN(CommentPosition) as CommentPosition
FROM tbPerson JOIN
tbComment
ON tbPerson.PersonID = tbComment.PersonID
GROUP BY FirstName, LastName;
Notice that CommentPosition was removed from the GROUP BY clause.
If comment position varies, try this:
SELECT FirstName, LastName, CommentPosition
FROM tbPerson
INNER JOIN (
SELECT PersonID, MIN(CommentPosition) AS CommentPosition
FROM tbComment
GROUP BY PersonID
) T1 ON tbPerson.PersonID = T1.PersonID
This will also handle the case of multiple people with the same name.
You can use SELECT DISTINCT FirstName, LastName, ...to get exactly what you want. Here's a tutorial on it.
http://www.mysqltutorial.org/mysql-distinct.aspx

select rows from a database table with common field in sqlite

i have a table as follows:
create table table1(id integer,firstname text,lastname text);
firstname lastname======== =========
1 ben taylor
2 rob taylor
3 rob smith
4 rob zombie
5 peter smith
6 ben smith
7 peter taylor
I want to select rows with a lastname , where the lastname must be shared by ben and rob and firstnames must be ben and rob.
Hence in the above table the result of the select query must be:
1 ben taylor
2 rob taylor
3 rob smith
6 ben smith
what must be the sql query to get the above results?
I tried - select * from table1 as a,table1 as b where a.firstname='ben' and b.firstname='rob' and a.lastname=b.lastname this joined all the resultant rows which is not what i inteneded.
You can use two filtering joins to demand that the lastname is shared with both a Ben and a Rob:
select *
from Table1 t1
join Table1 rob
on rob.firstname = 'rob'
and t1.lastname = rob.lastname
join Table1 ben
on ben.firstname = 'ben'
and t1.lastname = ben.lastname
where t1.firstname in ('ben', 'rob')
Live example at SQL Fiddle.
select *
from table1 where first_name = 'ben' or first_name = 'rob'
and last_name
in (select last_name from table1 where first_name = 'rob' and last_name
in (select last_name from table1 where first_name = 'ben'))

Select query which returns exect no of rows as compare in values of sub query

I have got a table named student. I have written this query:
select * From student where sname in ('rajesh','rohit','rajesh')
In the above query it's returning me two records; one matching 'rajesh' and another matching: 'rohit'.
But i want there to be 3 records: 2 for 'rajesh' and 1 for 'rohit'.
Please provide me some solution or tell me where i am missing.
NOTE: the count of result of sub query is not fix there can be many words there some distinct and some multiple occurrence .
Thanks
Your requirements are not clear, and I'll try to explain why.
Let's define table students
ID FirstName LastName
1 John Smith
2 Mike Smith
3 Ben Bray
4 John Bray
5 John Smith
6 Bill Lynch
7 Bill Smith
Query with WHERE clause:
FirstName in ('Mike', 'Ben', 'Mike')
will return 2 rows only, because it could be rewritten as:
FirstName='Mike' or FirstName='Ben' or FirstName='Mike'
WHERE is filtering clause that just says if existing row satisfy given conditions or not (for each of rows created by FROM clause.
Let's say we have subquery that returns any number of non distinct FirstNames
In case if SQ contains 'Mike', 'Ben', 'Mike' using inner join you can get those 3 rows without problem
Select ST.* from Students ST
Inner Join (Select name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Result will be:
ID FirstName LastName
2 Mike Smith
2 Mike Smith
3 Ben Bray
Note data are not ordered by order of names returning by SQ. If you want that, SQ should return some ordering number, eg.:
Ord Name
1. Mike
2. Ben
3. Mike
In that case query should be:
Select ST.* from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
Order By SQ.ord
And result:
ID FirstName LastName
2 Mike Smith (1)
3 Ben Bray (2)
2 Mike Smith (3)
Now, let's se what will happen if subquery returns
Ord Name
1. Mike
2. Bill
3. Mike
You will end up with
ID FirstName LastName
2 Mike Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
2 Mike Smith (3)
Even worse, if you have something like:
Ord Name
1. John
2. Bill
3. John
Result is:
ID FirstName LastName
1 John Smith (1)
4 John Bray (1)
5 John Smith (1)
6 Bill Lynch (2)
7 Bill Smith (2)
1 John Smith (3)
4 John Bray (3)
5 John Smith (3)
This is an complex situation, and you have to clarify precisely what requirement is.
If you need only one student with the same name, for each of rows in SQ, you can use something like SQL 2005+):
;With st1 as
(
Select Row_Number() over (Partition by SQ.ord Order By ID) as rowNum,
ST.ID,
ST.FirstName,
ST.LastName,
SQ.ord
from Students ST
Inner Join (Select ord, name from …. <your subquery>) SQ
On ST.FirstName=SQ.name
)
Select ID, FirstName, LastName
From st1
Where rowNum=1 -- that was missing row, added later
Order By ord
It will return (for SQ values John, Bill, John)
ID FirstName LastName
1 John Smith (1)
6 Bill Lynch (2)
1 John Smith (3)
Note, numbers (1),(2),(3) are shown to display value of ord although they are not returned by query.
If you can split the where clause in your calling code, you could perform a UNION ALL on each clause.
SELECT * FROM Student WHERE sname = 'rajesh'
UNION ALL SELECT * FROM Student WHERE sname = 'rohit'
UNION ALL SELECT * FROM Student WHERE sname = 'rajesh'
Try using a JOIN:
SELECT ...
FROM Student s
INNER JOIN (
SELECT 'rajesh' AS sname
UNION ALL
SELECT 'rohit'
UNION ALL
SELECT 'rajesh') t ON s.sname = t.sname
just because you've got a criteria in there two times doesn't mean that it will return 1 result per criteria. SQL engines usually just use the unique criteria - thus, from your example, there will be 2 criteria in IN clause: 'rajesh','rohit'
WHY do you need to return 2 results? are there two rajesh in your table? they should BOTH return then. You don't need to ask for rajesh twice for that to happen. What does your data look like? What do you want to see returned?
Hi i am query just as you give above and it give me all data that matches in the condition of in clause. just like your post
select * from person
where personid in (
'Carson','Kim','Carson'
)
order by FirstName
and its give me all records which fulfill this Criteria