Fetch data from 3 three tables whichever is not null - sql

I am trying to find the available address details from three tables.
When table 1 has the address details then get it from table1
If table 1 address has null value then consider table2,
If table 2 address has null value then consider table3, else display table1 address (null)
There are foreign keys in table 1 which can be used to join table 2 and 3 but they can be null as well in which case only data from table 1 to be considered.
In my query, I am able to join the tables when the foreign keys are available but in case they are null, the query doesn’t work!
I am not sure if I can add a ‘Case’ statement to ignore the ‘Join’ conditions in case the foreign keys are null.
Can someone please assist?
My Query is below :
SELECT donor.donor_num,
CASE
--WHEN donor.addr1 IS NULL THEN paraddress.addr1
--WHEN paraddress.addr1 IS NULL THEN enrparaddr.addr1
WHEN donor.addr1 IS NULL THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE
--WHEN donor.addr2 IS NULL THEN paraddress.addr2
--WHEN paraddress.addr2 IS NULL THEN enrparaddr.addr2
WHEN donor.addr2 IS NULL THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
--JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'
Please see attached image for the three tables

You can try below - using FULL OUTER JOIN & coalesce() function
SELECT donor.donor_num,
coalesce(donor.addr1,paraddress.addr1,enrparaddr.addr1) AS Address1,
coalesce(donor.addr2,paraddress.addr2,enrparaddr.addr2) AS Address2
FROM donor
FULL OUTER JOIN enrparaddr ON enrparaddr.par_code = donor.enrol_code
FULL OUTER JOIN paraddress ON paraddress.par_code = donor.par_code
WHERE donor_num = '17206'

SELECT donor.donor_num,CASE WHEN donor.addr1 IS NULL
THEN enrparaddr.addr1
ELSE donor.addr1
END AS Address1,
CASE WHEN donor.addr2 IS NULL
THEN enrparaddr.addr2
ELSE donor.addr2
END AS Address2
FROM donor
left join enrparaddr ON enrparaddr.par_code = donor.enrol_code
WHERE donor_num = '17206'

I would recommend:
SELECT d.donor_num,
coalesce(d.addr1, pp.addr1, epe.addr1) AS Address1,
coalesce(d.addr2, pp.addr2, epe.addr2) AS Address2
FROM donor d LEFT JOIN
paraddress pp
ON pp.par_code = d.par_code LEFT JOIN
enrparaddr epe
ON epe.par_code = d.enrol_code AND
pp.par_code IS NULL
WHERE d.donor_num = 17206 -- do not use single quotes for numbers
Notes:
You want a LEFT JOIN because you want all rows in donors.
You should be joining the tables in the order used for the COALESCE().
The second JOIN condition can be limited to cases where the first does not match.
Number constants should not use single quotes.

You can do this with simple Case .. When Statement:
Select Case
When A.ID is NULL And B.ID is NULL And C.ID is NULL Then -- when all columns contain null
NULL
When A.ID is NULL And B.ID is NULL Then
C.ID
When B.ID is NULL and C.ID is NULL Then
A.ID
When A.ID is NULL And C.ID is NULL Then
B.ID
End As ID
From A, B, C

Related

Not equal Null not working in sql server

I have a query given below
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] != null THEN Ap.Name ELSE B.[Name]END Name,
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id
In the Case When query I am trying to return the Name based on the b.ApId value.
But even if b.ApId is not null I am getting B.Name instead of Ap.Name.
Can anyone point out where I am going wrong.
!= will evaluate for values, while NULL is not a value.
So you have to either use IS NULL or IS NOT NULL to compare nulls.
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] is not null THEN Ap.Name ELSE B.[Name]END Name,
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id
Use IS NOT NULL, IS NULL to compare with NULL value, Or use ISNULL, COALESCE function
SELECT
B.[Date],
B.[Detail],
B.[Number],
B.[Total],
CASE WHEN B.[ApId] IS NOT NULL THEN Ap.Name ELSE B.[Name] END Name
-- ISNULL(Ap.Name, B.[Name]) as Name
-- COALESCE(Ap.Name, B.[Name],'') as Name
FROM [Bacs] B
LEFT JOIN Table ap ON b.ApId= ap.Id

Selecting different columns from databases

Hello I have two databases and each has the same tables. For example I have table called world and it has 4 columns: pkey1, pkey2,companyid, company_name
I made a query which searches for rows which have the same pkey1 and pkey2 but one or many of their other property is different in the 2 tables. My question is how can I see only the different properties?
Here is my query it selects the rows which have the same pkey1 and pkey2 how can I upgrade it to see the columns where there is difference in both databases and of course if there is no difference the result of the query should return NULL in the column here is an example what I want to achieve:
in first database (1,1,345,'Ron'), second database (1,1,377,'Ron') the result should be (1,1,345,null)
Basically to reference data in a different database, you'll need a database link, since you are using PostgreSQL, this documentation should help;
https://www.postgresql.org/docs/current/static/dblink.html
You'll need to use this command to create the link (in this case with a name);
SELECT dblink_connect('CONNECTIONNAME', 'REMOTEDBCONNECTIONSTRING');
Then you can use this new connection via a select query;
SELECT *
FROM dblink('CONNECTIONNAME','SELECT * FROM foo') AS t(a int, b text, c text[]);
And replace 'foo' with your 'world' table name, then change the AS into the variables that relate to pkey1, pkey2,companyid, company_name etc.
If your databases are linked, you can join both tables and with "case" statement check if the value has changed:
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from db1.dbo.world a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2
If you want to omit rows with no difference you can use "except":
select a.pkey1, a.pkey2,
case when a.companyid <> b.companyid then a.companyid else null end as companyid,
case when a.company_name <> b.company_name then a.company_name else null end as company_name
from (
select pkey1, pkey2, companyid, company_name
from db1.dbo.world
except
select pkey1, pkey2, companyid, company_name
from db2.dbo.world) a
inner join db2.dbo.world b on a.pkey1 = b.pkey1 and a.pkey2 = b.pkey2

Create overview table with true false values based on rows exist in child table

I have a table with cases, and another table with notifications.
For simplicity let's say the case table contains
id int
name nvarchar(100)
The notification table contains:
id int
caseid int
notificationtype string
Notification types can be either 'standard' or 'critical'.
I'd like an sql that can give me an overview for each case, and if they have any critical or standard notifications.
So a result like this:
CaseId CaseName StdNotification CriticalNotification
1 Test case yes no
I tried this SQL:
select distinct case.id as CaseId,
case.name as CaseName,
notifications.notificationtype,
case notifications when 'standard' then 'yes' else 'no' end as StdNotification,
case notifications when 'critical' then 'yes' else 'no' end as CriticalNotification
from cases
inner join notifications on Notifications.caseid = case.id
But this gives me duplicate rows for each combination
CaseId CaseName StdNotification CriticalNotification
1 Test case yes no
1 Test case no yes
So, how do I construct a sql that wil make some kind of "sum" and only return one row for each case?
You don't want distinct. You want group by. Your data structure suggests that a given case could have more than one notification, so I would go with counts using conditional aggregation:
select c.id as CaseId, c.name as CaseName,
sum(case when n.notificationtype = 'Standard' then 1 else 0 end) as NumStandard,
sum(case when n.notificationtype = 'Critical' then 1 else 0 end) as numCritical
from cases c left join
notifications n
on n.caseid = c.id
group by c.id, c.name;
You can convert these to "yes" and "no" using another case.
Also, note that I changed the inner join to a left join, so you'll get cases that have no notifications at all.
SELECT C.id as CaseId,
C.name as CaseName,
IIF(n1.notificationtype IS null, 'no', 'yes') as StdNotification,
IIF(n2.notificationtype IS null, 'no', 'yes') as CriticalNotification
FROM [case] C
left join notification n1
on C.id = n1.caseid and n1.notificationtype = 'standard'
left join notification n2
on C.id = n2.caseid and n2.notificationtype = 'critical'

incorrect joins - 1 row per result set

I trying to determine which people in my databases have either unsubscribed from my news letters, which people have bad email addresses and which dont have either. I have activities activities for both iUnsub' and 'iBadEmail'.
the code i wrote was
select distinct
n.id,
'Unsubscribe' =
case
when a.activity_type = 'iUnsub' then '1'
end,
'Bad Email' =
case
when a.activity_type = 'iBadEmail' then '1'
end
from name n
left join activity a on n.id = a.id
where n.id in
(
'1002421',
'1005587',
'1009073',
'1001102'
)
the results i receive creates 2 results for each id
id Unsubscribe Bad Email
1001102 NULL NULL
1002421 NULL NULL
1002421 1 NULL
1005587 NULL NULL
1005587 1 NULL
1009073 NULL 1
1009073 NULL NULL
i would like to the code to only give me one row for each id like below
id Unsubscribe Bad Email
1001102 NULL NULL
1002421 1 NULL
1005587 1 NULL
1009073 NULL 1
The problem is that you have multiple activity rows 3 or your names, and you are returning a row in the result for each activity. Name 1001102 either has no or only one activity which is neither Unsub or BadEmail.
select n.Id,
sum(case when a.activity_id = 'iUnSub' then 1 else 0 end) UnSub,
sum(case when a.activity_id = 'iBadEmail' then 1 else 0 end) BadEmail
from name
left outer join activity a on n.id = a.id
where a.activity
and n.id in
(
'1002421',
'1005587',
'1009073',
'1001102'
)
group by n.Id
This will give you a non-zero figure if UnSubbed or BadEmail, and if both are 0, then it's presumably OK.
The left outer join is for cases whene a name has no activity rows. If you don't include that then they will not be included in the output. If that's fine, change it to an inner join.

SQL find difference between two table

I need to compare email record (by email address) between two tables (Table A as Production data and B as old data) to find the difference and show the result in column such as "New", "Delete" and etc.
If exists in Table A, not in Table B, it should mark "New"
else if exists in Table B, not in Table A, it should mark "Delete"
if appears in both table, it should mark "Maintain"
I want the result like that
DisplayName LastName Diremail Result
==============================================
XXX XXX a#a.com New
ABC ABC 1#a.com Delete
DDD DDD 2#a.com Maintain
My code as follows:
SELECT b.DisplayName,
b.LastName,
b.diremail,
Result = CASE WHEN a.DirEmail IS NULL THEN 'New'
when b.DirEmail IS null then 'delete'
else 'Maintain'
END
FROM vHRIS_StaffDB b
LEFT JOIN HRIS_DL_Lists a
ON a.DirEmail = b.DirEmail
WHERE (
a.DirEmail IS NULL
OR a.DisplayName != b.DisplayName
)
but the data not correct as the code not return record which should "Delete"
(found in table b, not in table a)
pls advise. Thanks.
Sounds like you need full join instead of left join. Try this:
SELECT coalesce(b.DisplayName, a.DisplayName) DisplayName,
coalesce(b.LastName, a.LastName) LastName,
coalesce(b.diremail, a.diremail) diremail,
Result = CASE WHEN a.DirEmail IS NULL THEN 'New'
when b.DirEmail IS null then 'delete'
else 'Maintain'
END
FROM vHRIS_StaffDB b
FULL JOIN HRIS_DL_Lists a
ON a.DirEmail = b.DirEmail
WHERE (
a.DirEmail IS NULL
OR a.DisplayName != b.DisplayName
)