Getting records from 2 tables with common an uncommon columns - sql

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

Related

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

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

Reconciliation Automation Query

I have one database and time to time i change some part of query as per requirement.
i want to keep record of results of both before and after result of these queries in one table and want to show queries which generate difference.
For Example,
Consider following table
emp_id country salary
---------------------
1 usa 1000
2 uk 2500
3 uk 1200
4 usa 3500
5 usa 4000
6 uk 1100
Now, my before query is :
Before Query:
select count(emp_id) as count,country from table where salary>2000 group by country;
Before Result:
count country
2 usa
1 uk
After Query:
select count(emp_id) as count,country from table where salary<2000 group by country;
After Query Result:
count country
2 uk
1 usa
My Final Result or Table I want is:
column 1 | column 2 | column 3 | column 4 |
2 usa 2 uk
1 uk 1 usa
...... but if query results are same than it shouldn't show in this table.
Thanks in advance.
I believe that you can use the same approach as here.
select t1.*, t2.* -- if you need specific columns without rn than you have to list them here
from
(
select t.*, row_number() over (order by count) rn
from
(
-- query #1
select count(emp_id) as count,country from table where salary>2000 group by country;
) t
) t1
full join
(
select t.*, row_number() over (order by count) rn
from
(
-- query #2
select count(emp_id) as count,country from table where salary<2000 group by country;
) t
) t2 on t1.rn = t2.rn

select the highest record between two table

I have two table. One table contains graduation records and the second table contains post graduation records. A candidate must have graduation, but it is not necessarily to have post graduation.
My question is to select the post graduation record if the candidate has post graduation else only graduation.
table 1 graduation_table
rollno | degree | division
--------------------------
001 | B.tech | 1st
002 | B.sc | 1st
003 | BA | 1st
table 2 postgraduation_table
rollno | degree | division
--------------------------
002 | M.sc | 1st
the result must be
rollno | degree | division
--------------------------
001 | B.tech | 1st
002 | M.sc | 1st
003 | BA | 1st
You want all rows from graduation_table which do not have a row in postgraduation_table plus those in postgraduation_table. This can be expressed with a not exists and union query:
select gt.rollno, gt.degree, gt.division
from graduation_table gt
where not exists (select *
from postgraduation_table pg
where pg.rollno = gt.rollno)
union all
select rollno, degree, division
from postgraduation_table
order by rollno;
Online example: http://rextester.com/IFCQR67320
select
rollno,
case when p.degree is null then g.degree else p.degree end as degree,
case when p.division is null then g.division else p.division end as division
from
grad g
left join
post p using (rollno)
Or better as suggested in the comments:
select
rollno,
coalesce (p.degree, g.degree) as degree,
coalesce (p.division, g.division) as division
from
grad g
left join
post p using (rollno)
Take a union of both tables, and introduce a position column, to rank the relative importance of the two tables. The postgraduate table has a pos value of 1, and the graduate table has a value of 2. Then, apply ROW_NUMBER() over this union query and assign a row number to each rollno group of records (presumed to be either one or at most two records). Finally, perform one more outer subquery to retain the most important record, postgraduate first, graduate second.
SELECT rollno, degree, division
FROM
(
SELECT
rollno, degree, division,
ROW_NUMBER() OVER (PARTITION BY rollno ORDER BY pos) rn
FROM
(
SELECT p.*, 1 AS pos p FROM postgraduation_table
UNION ALL
SELECT p.*, 2 FROM graduation_table p
) t
) t
WHERE t.rn = 1;
This should make your needs :
SELECT dg.rollno, CASE WHEN pg IS NOT NULL THEN pg.degree ELSE gd.degree END AS degree, dg.division
FROM graduation_table AS dg
LEFT OUTER JOIN postgraduation_table AS pg USING (rollno)
GROUP BY dg.rollno, dg.division;
Hope this help.

Selecting Records Matching Two or More Related Tables

I have a 'persons' table:
person_id name
100 jack
125 jill
201 jane
And many sub-tables, that the person_id could be in:
'rowing'
id person_id
1 100
2 201
'swimming'
id person_id
1 125
2 201
'running'
id person_id
1 201
'throwing'
id person_id
1 125
2 201
I would like to be able to select all people who are involved in two activities, regardless of which two.
As the great #TimSchmelter (great first name) mentioned, you should really be having a single PersonActivities table with an id corresponding to the particular activity.
That being said, if you must work with your current schema, one option would be to UNION together the activity tables, and then count which persons have two or more records, meaning that they participated in two or more activities.
SELECT t1.person_id, t1.name
FROM persons
INNER JOIN
(
SELECT t.person_id, COUNT(t.person_id) AS activityCount
FROM
(
SELECT person_id FROM rowing
UNION ALL
SELECT person_id FROM swimming
UNION ALL
SELECT person_id FROM running
UNION ALL
SELECT person_id FROM throwing
) AS t
GROUP BY t.person_id
HAVING COUNT(t.person_id) > 1
) t2
ON t1.person_id = t2.person_id

Get number of different values in a column in Access

I've tried more or less all combinations of count and distinct (except the correct one :) ) in order to get the example below.
Input: table t1
NAME | FOOD
Mary | Apple
Mary | Banana
Mary | Apple
Mary | Strawberry
John | Cherries
Expected output:
NAME | FOOD
Mary | 3
John | 1
N.B. Mary has Apple in two rows but she has 3 as we have 3 different values in the column.
I only managed to get 4 in FOOD Column for her, but I need 3 :(
select a.name as NAME, a.count(name) as Food
from
(SELECT distinct NAME,Food from table)a
Start with a query which gives you unique combinations of NAME and FOOD:
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
Then you can use that as a subquery in another where you can GROUP BY and Count:
SELECT sub.NAME, Count(*) AS [FOOD]
FROM
(
SELECT DISTINCT t1.NAME, t1.FOOD
FROM t1
) AS sub
GROUP BY sub.NAME;
select a.name, sum(a.FoodCount) from(
select distinct name,COUNT(food) as FoodCount from #t1 group by name, food ) as a group by a.name order by 2 desc