I have 3 tables called CompanyInfo , IDInfo and PersonalInfo.
The objective is to fetch P.[First Name], P.[Last Name], I.PAN, C.DOB.
I can put left join or right join to cater this but the sequence of tables may change as it is an input to some tool and user may enter the table names in any sequence like user1 mentions "CompanyInfo, IDInfo, PersonalInfo", user2 mentions "IDInfo, PersonalInfo, CompanyInfo" and so on.
Table data is as below, Is there a way I can fetch the data through single SQL query (may be union). Say for if I want to fetch the data for ID = 4, I should get:
FirstName LastName PAN DOB
User Four UAN44444 NULL
If ID = 3
FirstName LastName PAN DOB
User THree NULL 1987-12-08
CompanyInfo Table
ID Company OfficialEmail EmpID DOB Department Joining Date Status
1 RBS userone#rbs.co.uk UK222222 1980-11-15 HR 2012-11-20 Inactive
3 Infosys userthree#infy.com IN333333 1987-12-08 Admin 2016-08-18 Inactive
5 IBM userfive#us.ibm.com US55555 1986-03-26 Finance 2014-06-26 Active
10 Samsung userten#samsung.com SK101010 1988-04-04 Admin 2013-04-07 Active
IDInfo Table
ID UAN TIN PAN
2 UAN22222 TIN222222 PAN22222
4 UAN44444 TIN444444 PAN44444
5 UAN55555 TIN555555 PAN55555
PersonalInfo Table
ID FirstName LastName PhoneNumber City Address ZipCode Email
1 User One +44-7432564125 London United Kingdom RG231FDT userone#gmail.com
2 User Two +91-987654321 New Delhi India 110006 usertwo#gmail.com
3 User Three +44-782136425 Guildford United Kingdom GUI74DS userthree#gmail.com
4 User Four +1-230156428 Atlanta United States GA 30337 userfour#gmail.com
5 User Five +1-650324152 Houston United States TX 77077 userfive#gmail.com
6 User Six +91-8885552223 Mumbai India 400012 usersix#gmail.com
7 User Seven +91-9998887771 Bangalore India 560021 userseven#gmail.com
Simple LEFT JOIN will resolve your problem.
SELECT P.FirstName, P.LastName, I.PAN, C.DOB
FROM PersonalInfo P
LEFT JOIN IDInfo I ON I.ID = P.ID
LEFT JOIN CompanyInfo C ON C.ID = P.ID
WHERE P.ID = #YourInput
You can use left join and right join:
SELECT P.FirstName, P.LastName, I.PAN, C.DOB. FROM IDInfo i LEFT JOIN PersonalInfo p ON p.ID = i.ID LEFT JOIN CompanyInfo c ON c.ID = i.ID WHERE i.ID = 3
Creating table variables to hold data of 3 table
DECLARE #CompanyInfo TABLE
(ID INT,Company NVARCHAR(50),OfficialEmail NVARCHAR(50),EmpID NVARCHAR(50),DOB NVARCHAR(50),Department NVARCHAR(50),[Joining Date] NVARCHAR(50),[Status] NVARCHAR(50))
DECLARE #IDInfo TABLE
(ID INT,UAN NVARCHAR(50),TIN NVARCHAR(50),PAN NVARCHAR(50))
DECLARE #PersonalInfo TABLE
(ID INT,FirstName NVARCHAR(50),LastName NVARCHAR(50),PhoneNumber NVARCHAR(50),City NVARCHAR(50),[Address] NVARCHAR(50),ZipCode NVARCHAR(50),Email NVARCHAR(50))
Populate data to the tables
INSERT INTO #CompanyInfo VALUES
(1,'RBS','userone#rbs.co.uk','UK222222','1980-11-15','HR','2012-11-20','Inactive'),
(3,'Infosys','userthree#infy.com','IN333333','1987-12-08','Admin','2016-08-18','Inactive'),
(5,'IBM','userfive#us.ibm.com','US55555','1986-03-26','Finance','2014-06-26','Active'),
(10,'Samsung','userten#samsung.com','SK101010','1988-04-04','Admin','2013-04-07','Active')
INSERT INTO #IDInfo VALUES
(2,'UAN22222','TIN222222','PAN22222'),
(4,'UAN44444','TIN444444','PAN44444'),
(5,'UAN55555','TIN555555','PAN55555')
INSERT INTO #PersonalInfo VALUES
(1,'User','One','+44-7432564125','London','United Kingdom','RG231FDT','userone#gmail.com'),
(2,'User','Two','+91-987654321','New Delhi','India','110006','usertwo#gmail.com'),
(3,'User','Three','+44-782136425','Guildford','United Kingdom','GUI74DS','userthree#gmail.com'),
(4,'User','Four','+1-230156428','Atlanta','United States','GA 30337','userfour#gmail.com'),
(5,'User','Five','+1-650324152','Houston','United States','TX 77077','userfive#gmail.com'),
(6,'User','Six','+91-8885552223','Mumbai','India','400012','usersix#gmail.com'),
(7,'User','Seven','+91-9998887771','Bangalore','India','560021','userseven#gmail.com')
Query to obtain the required output
SELECT
P.FirstName,
P.LastName,
I.PAN,
C.DOB
FROM
#PersonalInfo P LEFT JOIN #IDInfo I ON I.ID = P.ID
LEFT JOIN #CompanyInfo C ON C.ID = P.ID
WHERE
P.ID = 4
OUTPUT :-
FirstName LastName PAN DOB
User Four PAN44444 NULL
Related
Question: How to join tables using join clause without listing all the fields?
Data
Given two tables, Person and Address:
Person
name
address_id
Alice
10
Bob
11
Charlie
10
Address
id
street
city
10
William Street
NYC
11
Old Street
London
Desired result:
I'd like to join them with a record, like so:
name
address.street
address.city
Alice
William Street
NYC
Bob
Old Street
London
Charlie
William Street
NYC
However, I have many columns in both tables and I don't want to specify them all.
So something a bit like using EXCEPT but with the joined columns becoming nested in an address record:
SELECT * EXCEPT (address_id)
FROM person p
JOIN address a
ON p.address_id = a.id
Is this possible in BigQuery?
Consider below query:
SELECT p.* EXCEPT(address_id), (SELECT AS STRUCT a.* EXCEPT(id)) AS address
FROM Person p JOIN Address a ON p.address_id = a.id;
output:
You can join more tables with similar approach.
SELECT p.* EXCEPT(address_id),
(SELECT AS STRUCT a.* EXCEPT(id)) AS address,
(SELECT AS STRUCT j.* EXCEPT(name)) AS Job
FROM Person p
JOIN Address a ON p.address_id = a.id
JOIN Job j ON p.name = j.name;
output:
Here's some dumb example of i want to do.
Basically i need to join my "Person" table with my "Addres".
My country colcumn will be the strongest, i wanna join by it, but if my Person doesn't have a
country id i need to join it by City.
I've tried LATERAL join, but nothing has worked.
Table Addres:
id
city
country
1
null
3
2
11
null
Table Person:
id
name
city
country
1
null
3
null
2
11
null
2
you can use 'OR' in your join statement:
select * from person p
left join address a
on p.country = a.country
or p.city = a.city
You can run all this SQL and see the results here.
Skip to the results ands the ensuing problems to get to the meat of the issue.
I have a table of Clubs (a club as in a group or organization of people, like a "swim club" or a "knitting club").
DECLARE #club TABLE (
Id INT
,Name NVARCHAR(255)
);
INSERT INTO #club VALUES
(1, 'Swim Club')
,(2, 'Knitting Club')
,(3, 'Bridge Club');
I have a table of Members.
DECLARE #member TABLE (
Id INT
,Name NVARCHAR(255)
);
INSERT INTO #member VALUES
(1, 'John Jones')
,(2, 'Sally Smith')
,(3, 'Rod Roosevelt')
,(4, 'Bobby Burns')
,(5, 'Megan Moore');
Members can belong to many Clubs, and so there is a Membership table that connects Clubs to Members (and also describes the membership dues price).
DECLARE #membership TABLE (
Id INT
,Member INT --FK to #member
,Club INT --FK to #club
,Dues INT --the cost of membership
);
INSERT INTO #membership VALUES
(1,1,1,10)
,(2,1,2,5)
,(3,2,1,10)
,(4,2,3,20)
,(5,3,1,10)
,(6,3,2,5)
,(7,4,2,5)
,(8,4,3,20)
,(9,5,1,10)
,(10,5,3,20);
Most Members just pay their associated Dues. Some Members, however, are Sponsored by other Members. And so those Sponsored members will have their Dues paid by another Member (the Sponsor). Therefore, we have a Sponsorship table. The Sponsorship table connects Sponsors (paying for the Dues) to a Sponsee (having their Dues paid by a Sponsor) for a particular Club. Because a Sponsorship is specific to a Club, a Sponsorship record connects two Membership records and NOT two Member records.
DECLARE #sponsorship TABLE (
Id INT
,Sponsee_Membership INT --FK to Sponsee's #membership record
,Sponsor_Membership INT --FK to Sponsor's #membership record
);
INSERT INTO #sponsorship VALUES
(1,5,1)
,(2,8,4)
,(3,9,3)
,(4,10,4);
To get a full view of our Clubs/Memberships/Sponsors, we have:
SELECT
mship.Id AS 'Mship'
,mem.Name AS 'Member'
,c.Name AS 'Club'
,mship.Dues
,spons_mem.Name AS 'Sponsor'
FROM
#membership AS mship
JOIN #member AS mem
ON mship.Member = mem.Id
JOIN #club AS c
ON mship.Club = c.Id
LEFT JOIN #sponsorship AS spons
ON spons.Sponsee_Membership = mship.Id
LEFT JOIN #membership AS spons_mship
ON spons_mship.Id = spons.Sponsor_Membership
LEFT JOIN #member AS spons_mem
ON spons_mem.Id = spons_mship.Member;
which gives us these Results:
Mship Member Club Dues Sponsor
1 John Jones Swim Club 10 NULL
2 John Jones Knitting Club 5 NULL
3 Sally Smith Swim Club 10 NULL
4 Sally Smith Bridge Club 20 NULL
5 Rod Roosevelt Swim Club 10 John Jones
6 Rod Roosevelt Knitting Club 5 NULL
7 Bobby Burns Knitting Club 5 NULL
8 Bobby Burns Bridge Club 20 Sally Smith
9 Megan Moore Swim Club 10 Sally Smith
10 Megan Moore Bridge Club 20 Sally Smith
Sponsorships SHOULD span all shared memberships.
That is, if Sally sponsors Bobby, any time they are both in the same club, Sally will be identified as Bobby's sponsor.
We can see this in lines Mship=7 and Mship=8.
Bobby and Sally are both in the Bridge Club, so Sally is identified as Bobby's sponsor for his Bridge Club membership.
Sally is NOT a member of the Knitting Club, and so Bobby's Knitting Club membership does not show Sally as a sponsor.
Sorry for the long setup. Here's my actual question:
How can I identify where a Sponsorship is missing?
From the example, we have lines Mship=5 and Mship=6.
John is Rod's sponsor.
We can see the sponsorship for Rod's Swim Club membership.
Rod and John are also both Knitting Club members,
but Rod does not show John as a sponsor for his Knitting Club membership.
This is incorrect and this is what I am after.
I want to query all such missing sponsorships.
I can accomplish this using cursors / WHILE loops, but I know that such solutions are usually not taking a proper set-based approach. What would a proper query for this look like?
Many thanks.
Here is a SQL query that might respond to your requirement.
The logic is to use a subquery to generate a mapping between sponsors and sponsees based on mapping member.id instead of memberships.id ; for this, we use aggregation. Then, the outer query searches for clubs where both the sponsor and the sponsee participate, but for which no relation is declared in the sponsorship table
The query returns one record for each offending membership, with the sponsee and sponsor names.
SELECT mship1.Id, m1.Name Member, m2.Name Sponsor, c.Name Club, mship1.Dues
FROM
#membership mship1
INNER JOIN #club c ON c.Id = mship1.Club
INNER JOIN (
SELECT ms1.Member Sponsee_Member , MAX(ms2.Member) Sponsor_Member
FROM #sponsorship ss
INNER JOIN #membership ms1 ON ms1.Id = Sponsee_Membership
INNER JOIN #membership ms2 ON ms2.Id = Sponsor_Membership
GROUP BY ms1.Member
) rels ON rels.Sponsee_Member = mship1.Member
INNER JOIN #membership mship2 ON mship2.Member = rels.Sponsor_Member AND mship2.Club = mship1.Club
INNER JOIN #member m1 ON m1.Id = mship1.Member
INNER JOIN #member m2 ON m2.Id = mship2.Member
LEFT JOIN #sponsorship sship ON sship.Sponsor_Membership = mship2.Id
WHERE sship.Id IS NULL
;
In the rextester that you provided, this returns :
Id | Member | Sponsor | Club | Dues
-----|-----------------|--------------|----------------|-----
6 | Rod Roosevelt | John Jones | Knitting Club | 5
Working on creating this query got me thinking that you could optimize your database design. The current model will make it hard to maintain consistency : your question by itself demonstrates that. In the future, what happens if a sponsor registers in a new club, where one of his sponsee already participate ? Once again you will need to detect the missing sponshorship relation, and somehow create it.
You actually have a 1-1 relationship between sponsors and sponsee, since you stated that sponsorships SHOULD span all shared memberships. It does not look like you would allow a sponsee to have several sponsors, even across different clubs.
I would suggest that you drop the sponshorship table and store a self-foreign key to the sponsor directly in the member table. Starting from there, it is easy to check which clubs both members have in common, and properly assign the dues using a SQL query.
I found that I can gather this in a single query by gathering all Sponsored Relationships with a CTE, finding all memberships that SHOULD have a sponsorship based on that, then removing all existing sponsorships with an EXCEPT. I'm left with sponsorships that should exist but do not.
WITH sponsored_relationships AS (
SELECT DISTINCT
sponsee_member.Id AS Sponsee
,sponsor_member.Id AS Sponsor
FROM
#sponsorship AS s
JOIN #membership AS sponsee_mship
ON s.Sponsee_Membership = sponsee_mship.Id
JOIN #member AS sponsee_member
ON sponsee_mship.Member = sponsee_member.Id
JOIN #membership AS sponsor_mship
ON s.Sponsor_Membership = sponsor_mship.Id
JOIN #member AS sponsor_member
ON sponsor_mship.Member = sponsor_member.Id
)
SELECT
see_mem.Name AS Sponsee
,sor_mem.Name AS Sponsor
,c.Name AS Club
FROM
sponsored_relationships AS sr
JOIN #member AS see_mem
ON sr.Sponsee = see_mem.Id
JOIN #membership AS see_mship
ON see_mship.Member = see_mem.Id
JOIN #member AS sor_mem
ON sr.Sponsor = sor_mem.Id
JOIN #membership AS sor_mship
ON sor_mship.Member = sor_mem.Id
JOIN #club AS c
ON (see_mship.Club = c.Id
AND sor_mship.Club = c.Id
)
EXCEPT
SELECT
see_mem.Name AS Sponsee
,sor_mem.Name AS Sponsor
,c.Name AS Club
FROM
sponsored_relationships AS sr
JOIN #member AS see_mem
ON sr.Sponsee = see_mem.Id
JOIN #membership AS see_mship
ON see_mship.Member = see_mem.Id
JOIN #member AS sor_mem
ON sr.Sponsor = sor_mem.Id
JOIN #membership AS sor_mship
ON sor_mship.Member = sor_mem.Id
JOIN #club AS c
ON (see_mship.Club = c.Id
AND sor_mship.Club = c.Id
)
JOIN #sponsorship AS sship
ON (sship.Sponsee_Membership = see_mship.Id
AND sship.Sponsor_Membership = sor_mship.Id
);
I have two tables that contains People who are working at the company and their Employment information (so People is one table, Employment is another).
The People table contains information on where the person lives, emergency contact, phone number bla bla bla. The Employment table contains information on where he works, closest boss and more.
These tables have been corrupted and now contains a few duplicates by misstake. Now in both tables there is a Person id, but the employment id is only located in Employment. I want both numbers on all people that have been duplicated.
This works perfectly:
SELECT DISTINCT
pp.Personid,
pp.Firstname,
pp.Lastname,
pp.Address,
FROM People pp
JOIN People pp2
ON pp.Firstname = pp2.Firstname
AND pp.Lastname = pp2.Lastname
AND pp.Address = pp2.Address
AND pp.Personid <> pp2.Personid
ORDER BY pp.Firstname, pp.Lastname, pp.Personid
returning the following values (but does not include Employment number as you can see):
1001 Carl Johnsson Bigstreet 1
1002 Carl Johnsson Bigstreet 1
1003 Carl Johnsson Bigstreet 1
1010 Andrew Wilkinsson Smallstreet 2
1011 Andrew Wilkinsson Smallstreet 2
Now, to add the employment id I join in that table like this:
SELECT DISTINCT
pp.Personid,
e.Employmentid,
pp.Firstname,
pp.Lastname,
pp.Address,
FROM People pp
JOIN People pp2
ON pp.Firstname = pp2.Firstname
AND pp.Lastname = pp2.Lastname
AND pp.Address = pp2.Address
AND pp.Personid <> pp2.Personid
JOIN Employment e on pp.Personid = e.Personid
ORDER BY pp.Firstname, pp.Lastname, pp.Personid
And everything goes to h**l in a handbasket with the following result:
1001 1111 Carl Johnsson Bigstreet 1
1001 1111 Carl Johnsson Bigstreet 1
1001 1111 Carl Johnsson Bigstreet 1
1010 1234 Andrew Wilkinsson Smallstreet 2
1010 1234 Andrew Wilkinsson Smallstreet 2
As you can see I get both Personid and Employmentid but now I only get one of each (repeated the correct number of times) so I don't have all the different Personid and Employmentid in my list.
Why?
What happened with my join that crashed the party?
Ok, let's make some sample data;
CREATE TABLE #People (PersonID int, FirstName varchar(50), LastName varchar(50), Address1 varchar(50))
INSERT INTO #People (PersonID, FirstName, LastName, Address1)
VALUES
('1','Mike','Hunt','Cockburn Crescent')
,('2','Mike','Hunt','Cockburn Crescent')
,('3','Mike','Hunt','Cockburn Crescent')
,('4','Connie','Lingus','Dyke Close')
,('5','Connie','Lingus','Dyke Close')
,('6','Eric','Shun','Tickle Avenue')
,('7','Ivana','Humpalot','Bottom Street')
CREATE TABLE #Employment (PersonID int, EmploymentID int)
INSERT INTO #Employment (PersonID, EmploymentID)
VALUES
('1','10')
,('2','11')
,('3','12')
,('4','13')
,('5','14')
,('6','15')
,('7','16')
I'd do the first query differently, if you work out the duplicates in a sub-select it would be easier, you'll then be able to join to the employment table with no problems;
SELECT pp.PersonID
,em.EmploymentID
,pp.FirstName
,pp.LastName
,pp.Address1
FROM #People pp
JOIN (
SELECT FirstName
,LastName
,Address1
,COUNT(1) records
FROM #People
GROUP BY FirstName
,LastName
,Address1
HAVING COUNT(1) > 1
) pp2 ON pp.FirstName = pp2.FirstName
AND pp.LastName = pp2.LastName
AND pp.Address1 = pp2.Address1
LEFT JOIN #Employment em ON pp.PersonID = em.PersonID
Remember to clean up the temp tables;
DROP TABLE #People
DROP TABLE #Employment
I think you should try this
SELECT DISTINCT
ep.Personid,
ep.Employementid,
ep.FirstName,
ep.LastName,
ep.Address
FROM Person P join
(SELECT
pp.Personid,
e.Employmentid,
pp.Firstname,
pp.Lastname,
pp.Address,
from PP
JOIN Employment e on pp.Personid = e.Personid ) ep
on
P.Firstname = ep.Firstname
AND P.Lastname = ep.Lastname
AND P.Address = ep.Address
AND P.Personid <> ep.Personid
ORDER BY P.Firstname, P.Lastname, P.Personid
Sir please Check and reply to me
Your code should work and I am unable to reproduce your issue using data I have made up. The outcome you are seeing suggests to me that there are multiple person id's for carl johnsson in the employment table and that the employmentid is different - even though it looks the same in the output.
Can you supply your table definitions and sample data?
I have two tables Profile_Appointments and Profile.
Each record in the profile table has a Profile_key and a Profile_Type_Key in addition to other profile data - first name, last name, etc.
Rep's have Profile_Type 4, Customer's have Profile_Type 6
PROFILE TABLE
Profile_Key Profile_Type_key First_Name Last_Name
1234 4 John Smith
8765 6 Mike Jones
The Profile_Appointment table holds two records for each appointment one with the Rep's
Profile_Key the other with the customer's Profile_Key
Appointment_Key Profile_Key
10 1234
10 8765
The appointment_key refers to the Appointment table.
I need make a query that results in one record for each appointment and has both the rep and customer's data from the Profile table
THE RESULT I WANT
Appointment_Key Profile_Key Rep Profile_Key Customer
10 1234 8765
This is the query that's not working...
select appointment_key, p.profile_key as Rep, p2.profile_key as Customer, p.firs_name,p2.first_name from profile_appointment pa
join profile p
on p.profile_key = pa.profile_key
join profile p2
on p2.profile_key = pa.profile_key
where p.profile_type_key = '4' or p2.profile_type_key = '6'
What I get is:
Appointment_Key Rep Customer Rep Customer
10 1234 1234 John John
I can't figure out what I'm missing.
Thanks.
SELECT a1.appointment_key, a1.profile_key rep, a2.profile_key customer
FROM appointment a1
INNER JOIN profile p1 ON a1.profile_key = p1.profile_key AND p1.profile_type_key = 4
INNER JOIN appointment a2 ON a1.appointment_key = a2.appointment_key
INNER JOIN profile p2 ON a2.profile_key = p2.profile_key AND p2.profile_type_key = 6
EDIT: You might find nested selects more readable:
SELECT reps.appointment_key, reps.profile_key rep, customers.profile_key customer
FROM (
SELECT appointment.*
FROM appointment
INNER JOIN profile ON appointment.profile_key = profile.profile_key AND profile_type_key = 4
) reps
INNER JOIN (
SELECT appointment.*
FROM appointment
INNER JOIN profile ON appointment.profile_key = profile.profile_key AND profile_type_key = 6
) customers ON reps.appointment_key = customers.appointment_key
You need to satisfy both conditions so you need AND instead of OR
select pa.appointment_key, p.profile_key as Rep, p2.profile_key as Customer,
p.first_name as RepName,p2.first_name as CustomerName
from profile_appointment pa
join profile_appointment pa2 on pa.appointment_key = pa2.appointment_key
join profile p on p.profile_key = pa.profile_key and p.profile_type_key = '4'
join profile p2 on p2.profile_key = pa2.profile_key and p2.profile_type_key = '6'