SQL JOIN two tables with null values - sql

I am having a hard time figuring this query out. I need records from issueMaster based on userId and visible, joined to issueActionDetails that are visible, but there may not be any issueActionDetails. I am only getting issues that have actions.
SELECT
b.AssignedTo,
b.Visible,
c.ONEKEY_ID,
C.PHYS_NAME[Doctor],
B.IssueDescription[Issue to Address],
CASE WHEN A.ActionDescription IS NULL THEN 'To Be Assigned' ELSE A.ActionDescription END as [Action],
CASE WHEN A.AssignedTo IS NULL THEN 'To Be Assigned' ELSE A.AssignedTo END as [Assigned To],
CASE WHEN D.[Description] IS NULL THEN 'To Be Assigned' ELSE D.[Description] END As [Status]
FROM [dbo].[tbl_IssueMaster] B
LEFT JOIN [dbo].[tbl_IssueActionDetails] A ON A.IssueID =B.IssueID
INNER JOIN [dbo].[tbl_DoctorsNew] C ON B.OnekeyID =C.ONEKEY_ID
INNER JOIN [dbo].[Action_Status] D ON A.ActionStatus = D.ID
WHERE B.AssignedTo = #UserId AND B.Visible =1 AND A.Visible =1
ORDER BY c.ONEKEY_ID,B.DisplayOrder ,A.DisplayOrder

The "outerness" of the join to tbl_IssueActionDetails is negated by two things:
The inner join to Action_Status:
INNER JOIN [dbo].[Action_Status] D ON A.ActionStatus = D.ID
And the predicate in the WHERE clause
AND A.Visible =1
For any rows returned where there isn't a matching row in tbl_IssueActionDetails, the values in the columns for that table will all be NULL. (The database is essentially creating a row from tbl_IssueActionDetails that consists of all NULLs, and "matching" that row to the row from the table on the left side.
Any predicate that excludes NULL values from columns in that table will exclude that row. If we specify to only return rows where "A.Visible=1", that will exclude any rows that have a NULL value in that column. Which is what I meant when I said the "outerness" of the LEFT JOIN operation was negated.
The fix is to move the predicate to the ON clause of the join to tbl_IssueActionDetail
and change that INNER JOIN to an outer join LEFT JOIN

LEFT JOIN [dbo].[tbl_IssueActionDetails] A
ON A.IssueID = B.IssueID
AND A.Visible = 1
remove "AND A.Visible = 1" from the where clause, add it as a join condition instead
OR, alter the where clause to permit a NULL condition for the LEFT JOIN
WHERE B.AssignedTo = #UserId
AND B.Visible = 1
AND ( A.Visible = 1 OR A.Visible IS NULL)
If you always insist that A.Visible = 1 in the where clause you suppress the NULLs that a LEFT JOIN can provide. Be on guard for this whenever you use an outer join.

Related

Distinguishing which value is obtained from COALESCE by concatenating the value to a different prefix

SELECT COALESCE(grouped_wells.groupforecasting_id,wells.id) as the_id, string_agg(wells.name,', ') as well_name, sum(gas_cd) as gas_cd, date
FROM productions
INNER JOIN completions on completions.id = productions.completion_id
INNER JOIN wellbores on wellbores.id = completions.wellbore_id
INNER JOIN wells on wells.id = wellbores.well_id
INNER JOIN fields on fields.id = wells.field_id
INNER JOIN clusters on clusters.id = fields.cluster_id
LEFT JOIN grouped_wells on grouped_wells.wells_id = wells.id
LEFT JOIN groupforecasting on groupforecasting.id = grouped_wells.groupforecasting_id and groupforecasting.workspace_id = 3
GROUP BY the_id, productions.date
ORDER BY the_id, productions.date
In the above SQL, I am grouping by the_id that results from COALESCE. I want to avoid grouping grouped_wells.groupforecasting_id of equal value to wells.id.
One possible way is to add a prefix depending on which of the two value I got from COALESCE, either add "group_" or "well_".
How to add this conditional prefix to the_id?
If grouped_wells.groupforecasting_id is Null then concatenate "well_" to the result of COALESCE.
Else concatenate "group_" to the result of COALESCE.
You nearly had the solution in your
If grouped_wells.groupforecasting_id is Null then concatenate "well_"
to the result of COALESCE. Else concatenate "group_" to the result of
COALESCE.
In postgres you can use the case when syntax:
case when ... then ...
else ...
end as the_id
completing it in your select (and your comment):
SELECT
case when grouped_wells.groupforecasting_id is NULL then concat('well_', wells.id)
else
concat('group_', grouped_wells.groupforecasting_id)
end as the_id,
string_agg(wells.name,', ') as well_name,
sum(gas_cd) as gas_cd, date
FROM productions
INNER JOIN completions on completions.id = productions.completion_id
INNER JOIN wellbores on wellbores.id = completions.wellbore_id
INNER JOIN wells on wells.id = wellbores.well_id
INNER JOIN fields on fields.id = wells.field_id
INNER JOIN clusters on clusters.id = fields.cluster_id
LEFT JOIN grouped_wells on grouped_wells.wells_id = wells.id
LEFT JOIN groupforecasting on groupforecasting.id = grouped_wells.groupforecasting_id and groupforecasting.workspace_id = 3
GROUP BY the_id, productions.date
ORDER BY the_id, productions.date

SQL - How to return a value if nulls is returned

I am trying to write a query for a parameter in SSRS where if it doesn't pull back any data, it will put "None" in the parameter. Here is what I have tried:
select CASE
WHEN pt.propertynumber IS NOT NULL
THEN pt.propertynumber
ELSE 'None'
END AS "Field1"
from projectmaintenanceproperties pmp
left join projectmaintenances pm on pm.id = pmp.projectmaintenanceid
left join properties pt on pt.id = pmp.propertyid
where pm.id in (:Ops)
and pt.projectid in ( :Proj )
order by 1
When there is no data pulled back, it is not returning anything in Field1.
How can I tell it to return 'None'?
Okay, here's a bit of a nightmare that might do the trick. I'm doing this nightmare because I once had a query that very cleverly used UNION and NOT EXISTS to return a completely different query and that resulted in a disastrous query plan when that second query executed.
What I'm doing below is using a fake LEFT OUTER JOIN with a table of only one row to your desired values table. It's fake because the join predicate is always true. So for every row from your query that will column from the ForNone query will be returned as well, but ignored since coalesce will return the value from your query (unless it is null, and if that is a possibility you can add a check in your query). If there are no results from your query then only one row is returned because and coalesce will use the value 'None'.
SELECT COALESCE(src.Field1, ForNone.NoneField) AS "Field1"
FROM ( SELECT 'None' AS "NoneField" ) ForNone
LEFT OUTER JOIN (
select pt.propertynumber AS "Field1"
from projectmaintenanceproperties pmp
left join projectmaintenances pm on pm.id = pmp.projectmaintenanceid
left join properties pt on pt.id = pmp.propertyid
where pm.id in (:Ops)
and pt.projectid in ( :Proj )
order by 1
) src ON 1 = 1
Oops, comments are correct - my bad. You'll instead need an IF statement to check if any values are returned:
IF EXISTS
( select CASE
WHEN pt.propertynumber IS NOT NULL
THEN pt.propertynumber
ELSE 'None'
END AS "Field1"
from projectmaintenanceproperties pmp
left join projectmaintenances pm on pm.id = pmp.projectmaintenanceid
left join properties pt on pt.id = pmp.propertyid
where pm.id in (:Ops)
and pt.projectid in ( :Proj )
order by 1;
)
THEN select pt.propertynumber [Field1]
from projectmaintenanceproperties pmp
left join projectmaintenances pm on pm.id = pmp.projectmaintenanceid
left join properties pt on pt.id = pmp.propertyid
where pm.id in (:Ops)
and pt.projectid in ( :Proj )
order by 1;
ELSE
SELECT 'None' AS [Field1];
END IF;

left outer join doesnt return all rows on left table

set #fuel_type='hsd';
select
ro.ro_id,
(case
when if(#fuel_type='ms',r.ms_field_input_id,r.hsd_field_input_id)= 0
then if(#fuel_type='ms',concat(r.remark_ms,r.remark_branded),r.remark_hsd)
else
f.field_name
end )
from
retail_outlets ro left join
volume_trackers r on ro.ro_id=r.ro_id,
field_inputs_master f
where
if(#fuel_type='ms',r.ms_field_input_id = f.field_id,r.hsd_field_input_id=f.field_id)
and ro.pricing_module=1 and if(#fuel_type='ms',ro.ms,ro.hsd)=1 and r.date_inserted='2017-02-06'
;
I need to show all the ro_id in the retail_outlets table but only the ro_id that match with the volume trackers table are displayes
Not positive but I think this is what you're after.
changes are the following:
removed , notation and inject a left join
moved the r.date_inserted to the join criteria.
moved where clause for , join to new left join and altered to case statement as to why I used a left join... Since we tie back to R which is already a left join it made sense to me to continue with left joins...
removed some unneeded ()'s
Assumptions r.date_inserted is a varchar2 data type or '2017-02-06' is implicitly being cast correctly.
.
SET #fuel_type='hsd';
SELECT
ro.ro_id ,
CASE
WHEN IF(#fuel_type='ms',r.ms_field_input_id,r.hsd_field_input_id)= 0
THEN IF(#fuel_type='ms',concat(r.remark_ms,r.remark_branded),r.remark_hsd)
ELSE f.field_name
END
FROM retail_outlets ro
LEFT JOIN volume_trackers r
ON ro.ro_id = r.ro_id
AND r.date_inserted = '2017-02-06'
LEFT JOIN field_inputs_master f
ON f.field_id = CASE WHEN #fuel_type='ms'
THEN r.ms_field_input_id
ELSE r.hsd_field_input_id
END
WHERE ro.pricing_module=1
AND IF(#fuel_type ='ms',ro.ms,ro.hsd)=1;

Why is this SQL query returning this result?

Can anyone tell me why this sql query is returning this result.
SELECT
M.MatterNumber_Id, M.MatterNumber, M.MatterName,
ISNULL(MP.Role_Cd, 'No Primary') AS PrimaryRole,
ISNULL(E.Name, 'No Primary') AS PrimaryName,
ISNULL(C.CommNumber, 'l.w#abc.ca;m.j#abc.com') AS Email
FROM
Matter M
LEFT OUTER JOIN
MatterPlayer MP ON M.MatterNumber_Id = MP.MatterNumber_Id AND
MP.Role_Cd IN ('Primary Lawyer', 'Primary Staff Member') AND
MP.EndDate IS NULL
LEFT OUTER JOIN
Entity E on MP.Entity_EID = E.Entity_EID
LEFT OUTER JOIN Communication C on MP.Entity_EID = C.Entity_EID AND
C.CommunicationType_Cd = 'Email'
LEFT OUTER JOIN
MatterExposure ME on M.MatterNumber_Id = ME.MatterNumber_Id AND
ME.AssessedDate > '7/10/2014' AND
ME.Currency_CD IS NOT NULL
WHERE
M.MatterStatus_Cd = 'Active' AND
ME.AssessedDate IS NULL AND
M.Matter_Cd in
(SELECT
rpl.Type_CD
FROM
RuleProfile_Tabs rpt
INNER JOIN
RuleProfile_LookupCode rpl ON rpt.RuleProfile_ID = rpl.RuleProfile_ID
WHERE
tab_id = 1034 AND Caption LIKE 'Reportable Matter%')
ORDER BY
Email, M.MatterName
But When i see the results I check one of the records returned and it should not have been returned.
One of the results returned:
Bailey, Richard
In the db i check the values in the tables it should not have been returned because Currency_CD is null and in the sql it states currency_cd is not null. Also the assessed date is AFTER 7/10/2014
Table Values:
MatterStatus_CD:
Active
AssessedDate:
7/24/2014
Currency_CD:
NULL
EndDate:
NULL
Where clauses are used for filtering, not the join clause. Every JOIN should have an ON. Here's a head start.
Select M.MatterNumber_Id, M.MatterNumber, M.MatterName,
IsNull(MP.Role_Cd, 'No Primary') as PrimaryRole,
IsNull(E.Name, 'No Primary') as PrimaryName,
IsNull(C.CommNumber, 'l.w#abc.ca;m.j#abc.com') as Email
From Matter M
Left Outer Join MatterPlayer MP on M.MatterNumber_Id = MP.MatterNumber_Id
Left Outer Join Entity E on MP.Entity_EID = E.Entity_EID
Left Outer Join Communication C on MP.Entity_EID = C.Entity_EID
Left Outer Join MatterExposure ME on M.MatterNumber_Id = ME.MatterNumber_Id
Where M.MatterStatus_Cd = 'Active'
AND ME.AssessedDate is Null
and M.Matter_Cd in (select rpl.Type_CD
from RuleProfile_Tabs rpt
inner join RuleProfile_LookupCode rpl on rpt.RuleProfile_ID = rpl.RuleProfile_ID
where tab_id = 1034 AND Caption like 'Reportable Matter%')
and MP.Role_Cd In ('Primary Lawyer', 'Primary Staff Member')
and MP.EndDate is Null
and ME.AssessedDate > '7/10/2014'
and ME.Currency_CD IS NOT NULL
and C.CommunicationType_Cd = 'Email'
Order by Email, M.MatterName
You are LEFT JOINing MatterExposure onto Matter. Your Me.Currency_CD IS NOT NULL criteria in the LEFT JOIN's ON statement is only saying, "don't join to records where Currency_CD is null..." but because this is a left join, none of your Matter table's records are lost in the join. So when you ask for Currency_CD you will get NULL.
To remove records from your query where Currency_CD is null in the MatterExposure table you will either need to specify Currency_CD IS NOT NULL in your where statement (instead of your join) or will need to use an INNER JOIN to your MatterExposure table.
It is because this join is a LEFT OUTER JOIN. If you want to enforce this join make it an inner join. Or move that check to the WHERE clause.

SQL JOIN WIth null

What can I do do make my statement return Null when there is no row with D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973' and the Data Table?
I've tried Left JOIN But nothing changes... :(
SELECT
D.Value
FROM dbo.Item I
JOIN dbo.Data D ON D.ItemID = I.ID
WHERE I.ItemTypeID = '14ea6709-1bf8-4d5c-9090-3ace3cc42874' --Instance.album
AND D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973' --freepacks
You need a LEFT JOIN and to move the condition on D into the ON clause rather than WHERE. In the WHERE clause this converts your query back into an inner join.
SELECT D.Value
FROM dbo.Item I
LEFT JOIN dbo.Data D
ON D.ItemID = I.ID
AND D.MetaDataID = '580c215f-54cb-4449-8368-7d740be71973'
--freepacks
WHERE I.ItemTypeID = '14ea6709-1bf8-4d5c-9090-3ace3cc42874' --Instance.album
Make it a LEFT JOIN. Left joins will preserve every row from the original table (dbo.Item), even if the table being joined (dbo.Data) would be NULL. Of course, then you also can't require dbo.Data.anything to be nonzero in your on clause so you should probably remove that criterion.