full outer join on two keys - sql

I am trying to do merge two tables on phone numbers so that if I find phone in either of the tables then join the rest of the fields as shown below.
Now there are scenarios where phone doesn't exist in both the tables. Then the table should join on email_id, so basically first check if phone matches if not then check for email id match. If none then drop the record.
select COALESCE(icici.phone, hsbc.phone) as phone,
COALESCE(icici.email_id, hsbc.email_id) as email_id, city
from credit_card.icici
full outer join credit_card.hsbc on icici.phone = hsbc.phone
or icici.email_id = hsbc.email_id
limit 10
But I am getting this error
ERROR: FULL JOIN is only supported with merge-joinable or hash-joinable join conditions
SQL state: 0A000
Is there a way to solve it, or is there a better way to do this?

You can union the result of a left and a right join:
SELECT COALESCE(icici.phone, hsbc.phone) as phone,
COALESCE(icici.email_id, hsbc.email_id) as email_id, city
FROM credit_card.icici
LEFT OUTER JOIN credit_card.hsbc on icici.phone = hsbc.phone
OR icici.email_id = hsbc.email_id
UNION (
SELECT COALESCE(icici.phone, hsbc.phone) as phone,
COALESCE(icici.email_id, hsbc.email_id) as email_id, city
FROM credit_card.icici
RIGHT OUTER JOIN credit_card.hsbc on icici.phone = hsbc.phone
OR icici.email_id = hsbc.email_id
WHERE icici.id IS NULL
)
However, the right join may only contain the rows that were not found for any values from the left table. These rows are filtered out using WHERE, for example, by checking the primary key for NULL.

Use union all and aggregation:
select phone, max(email_id)
maxCOALESCE(icici.phone, hsbc.phone) as phone,
COALESCE(icici.email_id, hsbc.email_id) as email_id, city
from ((select phone, email_id
from credit_card.icici
) union all
(select phone, email_id
from credit_card.hsbc
)
) cc
group by phone,
(case when phone is null then email_id end);

Related

join table on condition

I have 3 tables user, student_data, teacher_data. A user can be either student or a teacher. If it is the teacher I want to join user and teacher_data. And if it is a student then I want to join user with student_data.
How I can do this join with the condition.
I'd combine the two data tables in a sub-query, and then join the users to that.
SELECT
*
FROM
usr u
LEFT JOIN
(
SELECT user_id, datum, xxx, NULL AS yyy FROM student_data
UNION ALL
SELECT user_id, datum, NULL, yyy FROM teacher_data
)
d
ON d.user_id = u.id
https://dbfiddle.uk/?rdbms=oracle_21&fiddle=9b801ea739d42fe50c00ef4e17eaf143
NOTES:
The columns selected from the two data tables must match
Any unmatched columns must either be skipped or filled with NULL
Please don't call a table user, it's a reserved keyword and Oracle won't allow it.
You can write it like this:
select u.user_id,
s.student_id,
t.teacher_id
from usr u
left join student_data s on u.user_id=s.student_id
left join teacher_data t on u.user_id=t.teacher_id
where s.student_id is not null or t.teacher_id is not null
order by u.user_id
For every user_id check if he is a student or teacher, if he is student get his student column values else null, if he is a teacher get his teacher column values else null.
maybe try a union - something like this
select user_id, user_other_stuff
from user, student_data
where user.user_id = student_data.user_id
UNION
select user_id, user_other_stuff
from user, teacher_data
where user.user_id = teacher_data.user_id

H2 making one select from 2

I got 3 tables, Users, courses and course realation tables. I want to get users who aren't on specific course. So I figure I need somehow merge 2 selects with right join. How could I make one select from 2 selects?
SELECT ID, NAME, LASTNAME, ROLE FROM COURSERELATION JOIN USERS ON
ID_USER = ID WHERE ID_COURSE = ?
RIGTH JOIN
SELECT ID, NAME, LASTNAME, ROLE from COURSERELATION JOIN USERS ON
ID_USER = ID WHERE ID_COURSE != ?
You need to extract users for which it doesn't exist a record of that user for the specific course. You can filter the rows using a NOT EXISTS clause over a subquery.
Please try below query:
SELECT u.ID,
u.NAME,
u.LASTNAME,
u.ROLE
FROM USERS u
WHERE NOT EXISTS (SELECT 1
FROM COURSERELATION s
WHERE s.id_user = u.id
AND s.id_course = 'YOUR_COURSE_ID_HERE' )

what is the proper union or sql construct to resolve these 2 datasets?

I have a table UserParent:
Id, FirstName, LastName
I have a table UserChild:
Id, ParentUserId (FK), ChildAttributeX
I have the following sample SQL:
SELECT Id, 0 ChildUserId, FirstName, LastName, NULL FROM UserParent
UNION
SELECT ParentUserId, Id, FirstName, LastName, ChildAttributeX FROM UserChild
Some Users may exist in both tables. All Users are stored with basic info in UserParent although some Users who have ChildAttributeX will have a FK ref to the UserParent in UserChild along with the ChildAttributeX in UserChild.
How can I resolve this as part of a UNION or some other SQL technique so all Users are included in the result set, without duplicate users?
I think this is what you are looking for. If all records must exist in parent table, this will return all records from parent, and any record that exist in child table, but only unique records (DISTINCT does that).
SELECT DISTINCT UP.ID, UP.FirstName, UP.LastName
FROM UserParent UP
LEFT OUTER JOIN UserChild UC ON UP.ID = UC.ParentUserID
If you are looking for all the records present in both table, you can try below query:
SELECT
coalesce(UP.Id,UC.ParentUserId),
0 ChildUserId,
(UP.FirstName,UC.FirstName),
(UP.LastName,UC.LastName),
NULL FROM
UserParent UP
FULL OUTER JOIN
UserChild UC
ON UC.ParentUserId = UP.ID

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

how use distinct in second join table in sql server

I have a SQL table consists of id, name, email,.... I have another SQL table that has id, email, emailstatus but these 2 id are different they are not related. The only thing that is common between these 2 tables are emails.
I would like to join these 2 tables bring all the info from table1 and if the email address from table 1 and table 2 are same and emailstatus is 'Bounced'. But the query that I am writing gives me more record than I expected because there are multiple rows in tbl_webhook(second table) for each row in Applicant(first table) .I want to know if applicant has EVER had an email bounce.
Query without join shows 23000 record but after join shows 42000 record that is because of duplicate how I can keep same 23000 record only add info from second table?
This is my query:
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
left outer join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[event]='bounced'
this is sample of desired data:
id email name emailFromTable2 emailstatus
1 test2#yahoo.com lili test2#yahoo.com bounced
2 tesere#yahoo.com mike Null Null
3 tedfd2#yahoo.com nik tedfd2#yahoo.com bounced
4 tdfdft2#yahoo.com sam Null Null
5 tedft2#yahoo.com james tedft2#yahoo.com bounced
6 tedft2#yahoo.com San Null
Use a nested select for this type of query. I would write this as:
select id, application, load, firstname, lastname, email,
(case when BouncedEmail is not null then email end) as EmailFromTable2,
BouncedEmail
from (SELECT A.[Id], A.[Application], A.[Loan], A.[Firstname], A.[Lastname], A.[Email],
(case when exists (select 1
from tbl_WebHook h
where A.Email = H.Email and H.[event] = 'bounced'
)
then 'bounced
end) as BouncedEmail
FROM Applicant A (NOLOCK)
) a
You can also do this with cross apply, but because you only really need one column, a correlated subquery also works.
;WITH DistinctEmails
AS
(
SELECT * , rn = ROW_NUMBER() OVER (PARTITION BY [Email] ORDER BY [Email])
FROM [tbl_Webhook]
)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK) left outer join DistinctEmails [H] (NOLOCK)
on A.Email = H.Email
WHERE H.rn = 1
and H.[event]='bounced'
i believe query below should be enough to select distinct bounced email for you, cheer :)
SELECT
A.[Id]
,A.[Application]
,A.[Loan]
,A.[Firstname]
,A.[Lastname]
,A.[Email],
,H.[Email], H.[EmailStatus] as BouncedEmail
FROM Applicant A (NOLOCK)
Inner join [tbl_Webhook] [H] (NOLOCK)
on A.Email = H.Email
and H.[EmailStatus]='bounced'
basically i just change the joining to inner join and change the 2nd table condition from event to emailstatus, if u can provide your table structure and sample data i believe i can help you up :)