If null in one table select from Other - sql

I have 2 tables inquiry and Application table I want to build a view that contains the user information based on data from these two tables.
Example
I Have Table Inquiry
FirstName, LastName, Address, email
I have table Application
FirstName, LastName, Address, email
Am querying the tables using the email field, This is what i want,
SELECT FirstName From InquiryTBL where email = #Email
If Null Select FirstName From ApplictionTBL where email = #email
This is kinda what I have been trying
SELECT
CASE
WHEN a.Email = null
THEN (SELECT FirstName from dbo.Inquiry_Tbl where email = #Email)
ELSE a.FirstName
END As [FirstName],

If email is in both tables, you can JOIN on that field and then use COALESCE to pull non-null data:
SELECT
Email = COALESCE( i.Email, a.Email)
, FirstName = COALESCE(i.FirstName, a.FirstName)
, LastName = COALESCE(i.LastName, a.LastNamej)
FROM InquiryTBL i
LEFT JOIN ApplicationTBL a
ON i.Email = a.Email

If the email is in both tables or in only one table, use a FULL OUTER JOIN on email inside a sub-select. Then you can filter that sub-select by the email address you need.
DECLARE #email varchar(20) = 'ted#excellent.com' ;
SELECT s1.FirsTName, s1.LastName, s1.Email
FROM (
SELECT COALESCE(i.FirstName, a.FirstName) AS FirstName
, COALESCE(i.LastName, a.LastName) AS LastName
, COALESCE(i.email, a.email) AS email
FROM InquiryTBL i
FULL OUTER JOIN ApplicationTBL a ON i.email = a.email
) s1
WHERE s1.Email = #email
;
https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=62d0f0a1026150de6b4fd9be3d058dbb
NOTE: To pick the first non-null value, you can use either coalesce() or isnull(). coalesce() is ANSI-compliant, can take more than 2 arguments and can be used in most databases. isnull() is primarily a Microsoft T-SQL function and takes only 2 arguments. It can be quicker in some cases than coalesce(), but it's not as portable. Both will also pick the first non-null value in your selected order, so you can change which value you want first.

Related

SQL: Eliminating duplicates with specific conditions

I have a SQL database that SOMETIMES has duplicate values, but only in one column (phone number). If there is a duplicate, the other attributes in the same row are filled in with NULL. In other cases, the phone number is not duplicated, but still has NULL values in the rows. Ex:
first_name
last_name
phone_number
john
smith
123-456-7890
NULL
NULL
123-456-7890
NULL
NULL
456-789-1011
carry
smith
121-314-1516
I'm trying to write a query that eliminates cases where the phone number is duplicated and the other values in the row are NULL, to get:
first_name
last_name
phone_number
john
smith
123-456-7890
NULL
NULL
456-789-1011
carry
smith
121-314-1516
Any ideas?
In cases like this you probably want a NOT EXISTS clause. This does a lookup for each row in the table, to see if there are any other records with the same phone number and populated name fields.
select
first_name,
last_name,
phone_number
from
phone_numbers pn
where
not exists (
select 1
from phone_numbers pn2
where pn2.phone_number = pn.phone_number
and pn.first_name is not null
and pn.last_name is not null
)
Although I'm not sure it's perfect. If there is a case where two records have the same phone number and both have NULL names then neither would be returned.
One way, might be to use a subquery to identify the phone_numbers only once.. and then outer join to the records you want without nulls. Something like this:
SELECT *
FROM
(SELECT phone_number AS root_phone_number
FROM table
GROUP BY phone_number
) AS phonenumbers
LEFT OUTER JOIN
(SELECT *
FROM table
WHERE first_name IS NOT NULL
) as notnulls
ON phonenumbers.phone_number = notnulls.phone_number
Here is the fastest way to do it, left join to the items you want to remove and then add a where clause for null results for the join. Every row that meets the join requirements WILL NOT be in the results.
I call this an Exclusionary Left Join.
SELECT *
FROM tableyoudidnotname main
LEFT JOIN tableyoudidnotname sub on
main.phone_number = sub.phone_number
and sub.first_name is null
and sub.last_name is null
WHERE sub.phone_number is null
I would use cte for it. Here's the code that does it.
with cte as (
select phone_number from phone_numbers
group by phone_number
having count(*) > 1
)
delete phone_numbers
where phone_number in (select phone_number from cte)
and first_name is null and last_name is null

full outer join on two keys

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);

Alias table that's actually a pivoted one?

I have this query:
SELECT
A.USERID
A.NAME
PVT.PHONE 'PROBABLY A CASE STATEMENT ON NULL WILL GO HERE...
PVT.ADDRESS 'ON HERE AS WELL...
FROM
USERS A
'I NEED TO CREATE A PIVOT TABLE HERE WITH THE ALIAS OF 'PVT' ON TABLE 'B'
B Contents:
UserID PHONE ADDRESS TYPE
1 444-555-2222 XXXXXXX PHONE
1 XXXXXXX 66 Nowhere NOTADDRESS
I want, on the same row, the user's phone by getting B.PHONE if TYPE = 'PHONE'.
I also want, on the same row, the user's address by getting B.ADDRESS content if TYPE = 'ADDRESS'.
As you see in the table dump above, I don't have a record matching the user ID AND TYPE = 'ADDRESS'
So I would need to show a blank or 'No address' in the main SELECT which will show the phone, but on the same row, blank or 'No address'.
I don't want to create an INNER JOIN because if there are no matching UserID's in B, the query will not return the info that I have in table A for that user.
Also, a LEFT JOIN will create two rows, which I don't want.
I think I pivoted table as alias would do it, but I don't know how to create such an alias.
Any ideas ?
How about using conditional aggregation?
SELECT A.USERID, A.NAME
B.PHONE, B.ADDRESS
FROM USERS A LEFT JOIN
(SELECT UserId, MAX(CASE WHEN TYPE = 'PHONE' THEN PHONE END) as PHONE,
MAX(CASE WHEN TYPE = 'ADDRESS' THEN ADDRESS END) as ADDRESS
FROM B
GROUP BY UserId
) B
ON B.UserId = A.UserId;
If you have to use PIVOT then you'd need the pivot in a subquery and left join to it
SELECT
A.USERID,
A.NAME,
PVT.PHONE,
PVT.[ADDRESS]
FROM
Users A
LEFT JOIN (SELECT *
FROM
(SELECT
UserID,
[Type],
(CASE [Type] WHEN 'PHONE' THEN PHONE WHEN 'ADDRESS' THEN [Address] END) Info
FROM UserInfo) AS UI
PIVOT (
MAX(Info)
FOR [Type] IN ([PHONE], [ADDRESS])
) P
) PVT ON A.UserID = PVT.UserID
This gives you pretty much the same execution plan as the conditional aggregation query, but not as easy on the eyes.
SQL Fiddle

Get ID from database matching multiple names

I have database with columns
ID FirstName LastName. I would like get the id of various people. Hence I am writing queries like the below.
Select ID from Database where FirstName='X' and LastName='x1'
Select ID from Database where FirstName='Y' and LastName='y1'
Select ID from Database where FirstName='Z' and LastName='z1'
I there any way to optimize this query.
You can simply put multiple condition in single where clause so just use them for simplicity.
Select ID from Database
where (FirstName='X' and LastName='x1') OR
(FirstName='Y' and LastName='y1') OR
(FirstName='Z' and LastName='z1')
with NULL Entries- You can add one more condition
OR (FirstName is NULL AND LastName is NULL)
If you want to get row even for those name which are not exists in your Database table (don't use this name for your table, BTW):
select a.FirstName, a.LastName, d.id
from (
select 'X', 'X1' union all
select 'Y', 'Y1' union all
select 'Z', 'Z1'
) as a(FirstName, LastName)
left outer join Database as d on d.FirstName = a.FirstName and d.LastName = a.LastName

What is wrong with this database query?

I have the following tables in a database (i'll only list the important attributes):
Person(ssn,countryofbirth)
Parents(ssn,fatherbirthcountry)
Employment(ssn, companyID)
Company(companyID, name)
My task is this: given fatherbirthcountry as input, output the names of companies where persons work whose countryofbirth match the fatherbirthcountry input.
I pretend that the fatherbirthcountry is Mexico and do this:
SELECT name
FROM Company
WHERE companyid = (SELECT companyid
FROM Employment
WHERE ssn = (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
but it is giving me an error:
>Scalar subquery is only allowed to return a single row.
am I completely off track? Can anybody please help?
The problem is that your subqueries are returning multiple results, so you have to use where in vs. =.
Change where ssn = to where ssn in, and where companyid = to where companyid in.
try using the IN keyword not '='.
try changing your query to this
SELECT name
FROM Company
WHERE companyid IN (SELECT companyid
FROM Employment
WHERE ssn IN (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
Use:
SELECT c.name
FROM COMPANY c
JOIN EMPLOYMENT e ON e.companyid = c.companyid
JOIN PERSON p ON p.ssn = e.ssn
AND p.countryofbirth = 'Mexico'
You should use In in the where condition since the (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico'); may return multiple ssn values.
SELECT name
FROM Company
WHERE companyid = (SELECT companyid
FROM Employment
WHERE ssn IN (SELECT ssn
FROM Person
WHERE countryofbirth = 'Mexico');
Try using IN instead of =
When you write:
select a from T where a = ( select....)
The sub-query must return a single value. In case if it returns multiple values, you get your error.
To solve this we use the IN operator which allows the sub-query to return a set of value (>=0) and your where condition succeeds if a equals any one of those values.
select a from T where a IN ( select....)
See if this works
SELECT c.Name FROM PERSON p
LEFT JOIN Employment e ON p.ssn=e.ssn
LEFT JOIN Company c ON
e.CompanyID=c.CompanyID WHERE
p.countryofbirth=
The error is due to the fact that the one of the two subqueries are returning multiple rows. I would think it likely that you have multiple people born in Mexico for example.
Select Name
From Companies
Where Exists(
Select 1
From Employment
Join Person
On Person.SSN = Employment.SSN
Join Parents
On Parents.SSN = Person.SSN
Where Parents.FatherBirthCountry = Person.CountryOfBirth
And Parents.FatherBirthCountry = #InputParam
And Employment.CompanyId = Companies.CompanyId
)
Ideally use the answer from OMG Ponies using JOINs.
But if you do not like JOINs for whatever reason, then TOP 1 should do the trick for you:
SELECT name
FROM Company
WHERE companyid =(SELECT TOP 1 companyid
FROM Employment
WHERE ssn = ( SELECT TOP 1 ssn
FROM Person
WHERE countryofbirth = 'Mexico');