Oracle SQL join with counts returning null - sql

I'm having a problem with the following query in Oracle SQL:
SELECT t.diif, t.mlf_response, v.total
FROM t_temp_rows t
LEFT OUTER JOIN
(SELECT a.diif, s.mlf_response, COUNT(a.customer_terid) total
FROM ter_details a
INNER JOIN lieu_details s ON a.lieu_id = s.lieu_id
WHERE a.customer_name = 'CUSTOMER_A' AND mlf_response IS NOT NULL
GROUP BY a.diif, s.mlf_response) v ON v.diif = t.diif AND v.mlf_response = t.mlf_response;
t_temp_rows contains all possible combinations for diif and mlf_response, regardless of whether they actually return counts in the subquery or not. I am hoping to get a count for every row in t_temp_rows, including 0 for rows with no count (I will add the NVL once it actually works).
If I run the query, rather than returning the counts in 'total' where there is a value and null elsewhere, I get null for every row.
Expected:
diif mlf_response total
---- ------------ -----
ABCD YES 12
ABCD NO 32
ABCE YES 54
ABCE NO 01
ABCF YES null
ABCF NO null
Actual:
diif mlf_response total
---- ------------ -----
ABCD YES null
ABCD NO null
ABCE YES null
ABCE NO null
ABCF YES null
ABCF NO null
What have I done wrong?

You need to add a.customer_name = 'CUSTOMER_A' to the left outer join because by adding it to the where, you are making it an inner join.
SELECT t.diif, t.mlf_response, v.total
FROM t_temp_rows t
LEFT OUTER JOIN
(SELECT a.diif, s.mlf_response, COUNT(a.customer_terid) total
FROM ter_details a ON a.customer_name = 'CUSTOMER_A'
LEFT OUTER JOIN lieu_details s ON a.lieu_id = s.lieu_id
WHERE mlf_response IS NOT NULL
GROUP BY a.diif, s.mlf_response) v ON v.diif = t.diif AND v.mlf_response = t.mlf_response;

Related

Flagging records with all missing values on right table when doing a left join

I have two tables representing client data for different years Left Table: 2019 and Right Table: 2018. Some of these clients did not exist for the prior year and my assumption is that when doing the left join, all field values from right table will be missing for those clients. Is there a way to flag these clients (or records)? Below is my query
create table joinedTable as
select a.unique_number, a.monthly_spend, b.unique_number, b.email_preference, b.client_tier,
from table2019 as a
left join table2018 as b
on a.unique_number = b.unique_number
Below is the desired output.
unique_number
monthly_spend
email_prefernce
client_tier
Flag
12AB56FG
2000
Yes
Special
0
32AB56FG
1200
Yes
Special
0
42AB56FG
2010
Yes
Special
0
56AB56HG
3000
Yes
Special
0
72AB58FG
6000
NULL
NULL
1
92AB56FG
800
NULL
NULL
1
Just use a case expression:
create table joinedTable as
select a.unique_number, a.monthly_spend, b.unique_number,
b.email_preference, b.client_tier,
(case when b.unique_number is null then 1 else 0 end) as flag
from table2019 a left join
table2018 b
on a.unique_number = b.unique_number;

Is there any way to show the records using same query?

I want to list out notices which are not sent. So I tried the query like below. But its showing wrong result. Is there any way to show notices which are not sent using the following query.
SELECT
vtn.*,
vn.id as notice_id,
vn.vnotice_datetime as sent_notice_time
FROM
vtemplates vt
LEFT JOIN vtemplate_notices vtn ON( vtn.vtemplate_id = vt.id)
LEFT JOIN vnotices vn ON(vn.vtemplate_notice_id = vtn.id AND vn.vnotice_datetime IS nULL)
LEFT JOIN violations v ON ( v.vtemplate_id = vt.id)
WHERE
v.id = 1
Records in a violation_notices table are as follows:
--------------------------------------------------------------
id vtemplate_notice_id desc vnotice_datetime created_on
---------------------------------------------------------------
1 1 test1 22/12/2018 05:30 22/12/2018
Expected Result:
id vtemplate_id created_on notice_id sent_notice_time
---------------------------------------------------------------
2 1 23/12/2018 NULL NULL
3 1 24/12/2018 NULL NULL
4 1 24/12/2018 NULL NULL
Actual Result:
id vtemplate_id created_on notice_id sent_notice_time
---------------------------------------------------------------
1 1 22/12/2018 NULL NULL
2 1 23/12/2018 NULL NULL
3 1 24/12/2018 NULL NULL
4 1 24/12/2018 NULL NULL
In actual result, it shows first record (which should not come) for which vnotice_datetime is NOT NULL but still it's showing.
Well, left joins don't remove non matching rows. Shifting the IS NULL check from the ON to the WHERE clause might work.
SELECT vtn.*,
vn.id notice_id,
vn.vnotice_datetime sent_notice_time
FROM vtemplates vt
LEFT JOIN vtemplate_notices vtn
ON vtn.vtemplate_id = vt.id
LEFT JOIN vnotices vn
ON vn.vtemplate_notice_id = vtn.id
LEFT JOIN violations v
ON v.vtemplate_id = vt.id
WHERE v.id = 1
AND vn.vnotice_datetime IS NULL;
You can use NOT EXISTS or test the joined column IS NULL in the WHERE clause
https://dev.mysql.com/doc/refman/8.0/en/exists-and-not-exists-subqueries.html
e.g
SELECT * FROM violations
WHERE NOT EXISTS(
SELECT * FROM notifications
WHERE violation_id = violations.id
)
SELECT v.*, n.* FROM violations v
LEFT JOIN notifications n
ON n.violation_id = v.id
WHERE n.violation_id IS NULL

LEFT OUTER JOIN not always matching

I'm starting with a SQL query with a couple of joins and I'm getting the exact data I expect. This is what the current query is.
SELECT DISTINCT o.OrganizationHierarchyUnitLevelFourCd, o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm
FROM Lab_Space l
JOIN Worker w ON l.Contact_WWID = w.WWID AND w.Employee_Status_Code = 'A'
JOIN Org_Hierarchy o ON o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL AND w.Org_Hierarchy_Unit_Cd = o.OrganizationHierarchyUnitCd
ORDER BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm
This ends up with a row like
1234 | Finance | IT
Now I've created a new table, where I'm tracking whether or not I want to include the organization in my output. That table just has two columns, an org ID and a bit field. So I thought I could LEFT OUTER JOIN, since the second table won't have data on all orgs, so I expanded the query to this:
SELECT DISTINCT o.OrganizationHierarchyUnitLevelFourCd, o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm, v.Include
FROM Lab_Space l
JOIN Worker w ON l.Contact_WWID = w.WWID AND w.Employee_Status_Code = 'A'
JOIN Org_Hierarchy o ON o.OrganizationHierarchyUnitLevelThreeNm IS NOT NULL AND w.Org_Hierarchy_Unit_Cd = o.OrganizationHierarchyUnitCd
LEFT OUTER JOIN Validation_Email_Org_Unit_Inclusion v ON o.OrganizationHierarchyUnitCd = v.OrganizationHierarchyUnitCd
ORDER BY o.OrganizationHierarchyUnitLevelThreeNm, o.OrganizationHierarchyUnitLevelFourNm
The problem I have is now I end up with rows like so:
1234 | Finance | IT | NULL
1234 | Finance | IT | 1
Since the Validation_Email_Org_Unit_Inclusion table includes a 1 for the 1234 org, I would expect to just get a single row with a value of 1, not include the row with NULL.
What have I done wrong?
You output OrganizationHierarchyUnitLevelFourCd but currently join on OrganizationHierarchyUnitCd. Join on the same column you output to get the corresponding value.
SELECT DISTINCT o.OrganizationHierarchyUnitLevelFourCd, ...
...
LEFT OUTER JOIN Validation_Email_Org_Unit_Inclusion v ON o.OrganizationHierarchyUnitLevelFourCd = v.OrganizationHierarchyUnitCd
...

SQL Server Return Null if exists

In SQL Server 2008 I am looking to create a query that will return a NULL in an aggregate if one exists, otherwise I'm looking for the maximum. This is a simplified example...
I have the following data:
CO Loc Term_Dt
1 A 7/15/2013
1 B
1 C 10/30/2000
2 A 8/10/2008
2 B 6/1/2015
2 C 4/30/2010
The result I'm looking for is:
CO Term_Dt
1 NULL
2 6/1/2015
because technically the Company is still open if at least one location has not yet been terminated.
Thanks
Just use aggregation and a case statement:
select co,
(case when count(term_dt) = count(*) then max(term_dt)
end) as term_dt
from table t
group by co;
count(<column>) counts the number of non-NULL values. If this doesn't match all the rows, then at least one is NULL. No else is needed for the case, because the default is NULL.
Generate a sub set of data with companies having null term dates and left join your super set to it. Any records in 2nd table which are not null you want to display as null so use a case statement.
This works because our outer table (A) returns
CO TERM_DT
1 7/15/2013
2 6/1/2015
But then our LEFT join on our inline view also adds B.Co...
CO TERM_DT B.CO
1 7/15/2013 1
2 6/1/2015 NULL
So you can see by saying we want to display NULL when B.CO is not null instead of the max(TERM_DT) will yield the desired results. This is accomplished using a case statement.
SELECT A.Co,
Case when B.CO is not null then Max(A.Term_DT) else NULL end as Term_DT
FROM tableName A
LEFT JOIN (SELECT Distinct CO from tableName where Term_dt is null) B
on A.Co = B.CO
GROUP BY CO

Update Select Join with NULL values

I have two Tables STR_IndentDetail and PUR_POIndent
STR_IndentDetail:
IndentID ItemID POQty D1 D2 D3 RD
--------- ------- ------ ---- --- --- ---
2 1 NULL 10 20 30 NULL
2 6 NULL 20 40 60 45
PUR_POIndent:
POID IndentID ItemID Quantity D1 D2 D3 RD
------ ---------- ------ ---------- ---- --- --- ---
2 2 1 55 10 20 30 NULL
2 2 6 100 20 40 60 45
I want to Update STR_IndentDetail table POQty with PUR_POIndent table Quantity.
I have written two Update Statement based on INNER JOIN and LEFT OUTER. But both the Queries Update only one row which has values in the Columns D1, D2, D3 and RD.
The row which contains the Column RD with NULL value is not getting UPDATE. How to write the Update Statement for this case. Below are my two Update Statements.
Based On Inner Join:
UPDATE STR_IndentDetail
SET
POQty = PUR_POIndent.Quantity
FROM
PUR_POIndent
WHERE
PUR_POIndent.IndentID = STR_IndentDetail.IndentID AND
PUR_POIndent.ItemID = STR_IndentDetail.ItemID AND
PUR_POIndent.D1 = STR_IndentDetail.D1 AND
PUR_POIndent.D2 = STR_IndentDetail.D2 AND
PUR_POIndent.D3 = STR_IndentDetail.D3 AND
PUR_POIndent.RD = STR_IndentDetail.RD
AND PUR_POIndent.POID = 2
Based On Left Join:
UPDATE STR_IndentDetail
SET
POQty = PUR_POIndent.Quantity
FROM
STR_IndentDetail LEFT OUTER JOIN PUR_POIndent ON
PUR_POIndent.IndentID = STR_IndentDetail.IndentID AND
PUR_POIndent.ItemID = STR_IndentDetail.ItemID AND
PUR_POIndent.D1 = STR_IndentDetail.D1 AND
PUR_POIndent.D2 = STR_IndentDetail.D2 AND
PUR_POIndent.D3 = STR_IndentDetail.D3 AND
PUR_POIndent.RD = STR_IndentDetail.RD WHERE
PUR_POIndent.POID = 2
Both the Queries ignores the row whose RD value is NULL.
I want to update both the rows. How to do this? Any Suggestions please.
You can't compare NULL values with =. Change the condition to use ISNULL and pass a value that isn't present in your table.
example
ISNULL(PUR_POIndent.RD, -999) = ISNULL(STR_IndentDetail.RD, -999)
NULL Comparison Search Conditions
Care must be taken when comparing null
values. The behavior of the comparison
depends on the setting of the SET
ANSI_NULLS option.
When SET ANSI_NULLS is ON, a
comparison in which one or more of the
expressions is NULL does not yield
either TRUE or FALSE; it yields
UNKNOWN. This is because a value that
is unknown cannot be compared
logically against any other value.
This occurs if either an expression is
compared to the literal NULL, or if
two expressions are compared and one
of them evaluates to NULL. For
example, the following comparison
always yields UNKNOWN when ANSI_NULLS
is ON:
or
PUR_POIndent.RD=STR_IndentDetail.RD OR
(PUR_POIndent.RD IS NULL AND STR_IndentDetail.RD IS NULL)