In SQL , how do I JOIN a column that is usually null so that the data is still retrieved? - sql

I want to incorporate a new column into a working SQL query.
However, it causes the whole query return nothing at all(because the column is mostly null in the database) .
Here's my pared-down code so far :
SELECT DISTINCT submittedRow.PERFORMED_DATE as "submitted",
supervisorRow.PERFORMED_DATE as "superv",
/* coalesce(sodRow.PERFORMED_DATE, TO_DATE('2000/07/07', 'YYYY/MM/DD') ) */ null AS "SOD"
hhs_umx_resp_activity submittedRow
join hhs_umx_resp_activity supervisorRow ON supervisorRow.reg_request_id = configRow.reg_request_id
/* join hhs_umx_resp_activity sodRow ON sodRow.reg_request_id = approvedRow.reg_request_id */
left join HHS_UMX_REG_REQUESTS hurr on hurr.reg_request_id = hur.reg_request_id
WHERE
and supervisorRow.ACTIVITY_RESULT_CODE = 'ASP'
AND submittedRow.activity_result_code = 'SBT'
/* AND sodRow.activity_result_code = 'ASD'*/
and hur.REG_REQUEST_ID IN ('262097')
The column that is mostly null, which I want to add in, is sodRow ( that's why the code AND sodRow.activity_result_code = 'ASD' is commented ).
Whenever I put back the extra join for sodRow , it just nulls out everything and I get no results at all. But I want it to work like a NVL or COALESCE, where it only displays that column if it exists, and otherwise just shows everything else.
I tried to create a view first in the code, then to do UNION on it. But it seems like view are only for PL/SQL code.
I also tried the outer joins, but this doesn't work.
I think the problem may be in the WHERE condition of my join code. I did like Dmitri suggest belwo :
AND nvl(sodRow.activity_result_code, 'ASD') = 'ASD'
AND nvl(configRow.activity_result_code, 'ACL') = 'ACL'
or also alternatively :
problem is that it won't return any rows. I.E If we're looking for 'ACL' then the previous check of 'ASD' becomes true and will render the next check useless.
I think I'm just having trouble visualizing how the joins work here
, thanks !

May be you can try left outer join
left outer join hhs_umx_resp_activity sodRow ON sodRow.reg_request_id = approvedRow.reg_request_id
and nvl
AND nvl(sodRow.activity_result_code, 'ASD') = 'ASD'
it will return records with null in sodRow.activity_result_code or 'ASD' in it

Related

Issue With SQL Pivot Function

I have a SQL query where I am trying to replace null results with zero. My code is producing an error
[1]: ORA-00923: FROM keyword not found where expected
I am using an Oracle Database.
Select service_sub_type_descr,
nvl('Single-occupancy',0) as 'Single-occupancy',
nvl('Multi-occupancy',0) as 'Multi-occupancy'
From
(select s.service_sub_type_descr as service_sub_type_descr, ch.claim_id,nvl(ci.item_paid_amt,0) as item_paid_amt
from table_1 ch, table_" ci, table_3 s, table_4 ppd
where ch.claim_id = ci.claim_id and ci.service_type_id = s.service_type_id
and ci.service_sub_type_id = s.service_sub_type_id and ch.policy_no = ppd.policy_no)
Pivot (
count(distinct claim_id), sum(item_paid_amt) as paid_amount For service_sub_type_descr IN ('Single-occupancy', 'Multi-occupancy')
)
This expression:
nvl('Single-occupancy',0) as 'Single-occupancy',
is using an Oracle bespoke function to say: If the value of the string Single-occupancy' is not null then return the number 0.
That logic doesn't really make sense. The string value is never null. And, the return value is sometimes a string and sometimes a number. This should generate a type-conversion error, because the first value cannot be converted to a number.
I think you intend:
coalesce("Single-occupancy", 0) as "Single-occupancy",
The double quotes are used to quote identifiers, so this refers to the column called Single-occupancy.
All that said, fix your data model. Don't have identifiers that need to be quoted. You might not have control in the source data but you definitely have control within your query:
coalesce("Single-occupancy", 0) as Single_occupancy,
EDIT:
Just write the query using conditional aggregation and proper JOINs:
select s.service_sub_type_descr, ch.claim_id,
sum(case when service_sub_type_descr = 'Single-occupancy' then item_paid_amt else 0 end) as single_occupancy,
sum(case when service_sub_type_descr = 'Multi-occupancy' then item_paid_amt else 0 end) as multi_occupancy
from table_1 ch join
table_" ci
on ch.claim_id = ci.claim_id join
table_3 s
on ci.service_type_id = s.service_type_id join
table_4 ppd
on ch.policy_no = ppd.policy_no
group by s.service_sub_type_descr, ch.claim_id;
Much simpler in my opinion.
for column aliases, you have to use double quotes !
don't use
as 'Single-occupancy'
but :
as "Single-occupancy",

How to make different behavior when 'select all' is selected on a multivalue parameter

I have a reporting services report and a stoproc. The report has a multivalue parameter that is being used like this:
<QueryParameter Name="#Aannemer">
<!-- Joins the multivalue selection into a single comma separated string. -->
<Value>=Join(Parameters!Aannemers.Value,",")</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
The stoproc splits the multivalue parameter using string_split. The stoproc is very long so here is a smaller version of it:
#Aannemer AS NVARCHAR(max) = NULL
[...]
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
WHERE (UI.Uitvoerder IN(select value from string_split(#Aannemer,',')) OR #Aannemer IS NULL )
This all works like a charm so far.
If a user selects 'select all' for the Aannemer parameter, he wants to see all Proefvak's and not filter on Aannemers at all.
But if a Proefvak exists that has no Meetvak connected to it, the Proefvak will never be listed (because the Meetvak holds the Uitvoerder and the Proefvak has no Meetvak). The user still wants to see the Proefvak that has no Meetvak.
Is there a way to check in the stoproc whether the user has selected 'select all', so I can return all Proefvak's?
I hope you understand what I am trying to accomplish. I am a noob when it comes to SQL, so please be clear with the complex parts. Thanks in advance!
==EDIT==
Trying to use #EddiGordo's solution, that looks promising. The next problem is that the #Aannemer parameter does not include the value 'Select All', because this is not a real value. So I tried to edit the code on the SSRS side like this:
<QueryParameter Name="#Aannemer">
<!-- Joins the multivalue selection into a single comma separated string. This paramater should be split up in the stored procedure. -->
<Value>
=IIF(Parameters!Aannemers.Count = COUNT(1, "Aannemers")
, "Select All",
Join(Parameters!Aannemers.Value,","))
</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
But I cannot deploy the SSRS code like this, I get this error:
"The expression used for the parameter '#Aannemer' in the dataset '#Aannemer' includes an aggregate or lookup function. Aggregate and lookup functions cannot be used in query parameter expressions."
Try this:
IF #Aannemer IS NULL
BEGIN
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
END
ELSE
BEGIN
SELECT DISTINCT PV.ProefvakID
FROM [dbo].[Proefvak] PV
LEFT OUTER JOIN Meetvak MV ON MV.ProefvakID = PV.ProefvakID
LEFT OUTER JOIN Uitvoerder UI ON UI.UitvoerderID = MV.UitvoerderID
WHERE UI.Uitvoerder IN(select value from string_split(#Aannemer,','))
END
try changing :
OR #Aannemer IS NULL
by
OR nullIf(#Aannemer, 'Select All') Is Null
in the where clause of your IN(Select... condition

How to give change working of having function dynamicaly on executing an sql statement?

I'm having a Sql code like as follows
Select a.ItemCode, a.ItemDesc
From fn_BOM_Material_Master('A', #AsOnDate, #RptDate, #BranchID, #CompID)a
Left Outer Join fn_INV_AsOnDate_Stock(#StockDate, #AsOnDate, #RptDate, #BranchID, #CompID, #Finyear)b
On a.ItemCode=b.ItemCode and b.WarehouseCode<>'WAP'
and a.BranchID=b.BranchID and a.CompID=b.COmpID
Where a.ItemNatureCode = 'F' and a.BranchID = #BranchID and a.CompID = #CompID
Group by a.ItemCode, a.ItemDesc
Having sum(b.CBQty)<=0
Here the problem is that im passing an "#ShowZeroStock" value as as bit if the "#ShowZeroStock" value is '1' then Having should not be validated or (i.e: All values from the table should be returned including zero)
So How to change the query based on passed bit value "#ShowZeroStock"
I can Use "If else " condition at the top and remove having in else part, but for a lengthy query i can't do the same.
Is this the logic you want?
Having sum(b.CBQty) <= 0 or #ShowZeroStock = 1

Conditional Sql in Daisy chained Query

I have one master table with all the IDs to each child table. The SQL statement looks like this...
SELECT Class.Descript
, Regulation.Descript AS Reg
, Compgroup.Descript AS Grouping
, Category.Descript AS Cat
, Exempt.Descript AS Exempt
, Reason.Descript AS Reasons
, COALESCE(ComponentRuleSet.NormalType, ComponentRuleSet.Supertype, '') AS Type
FROM ComponentRuleSet
LEFT OUTER JOIN Reason
ON ComponentRuleSet.ComponentCategoryID = Reason.ComponentCategoryID
LEFT OUTER JOIN Class
ON ComponentRuleSet.ComponentClassID = Class.ComponentClassID
LEFT OUTER JOIN Regulation
ON ComponentRuleSet.RegulationID = Regulation.RegulationID
LEFT OUTER JOIN Compgroup
ON ComponentRuleSet.ComplianceGroupID = Compgroup.ComplianceGroupID
LEFT OUTER JOIN Category
ON ComponentRuleSet.ComponentCategoryID = Category.ComponentCategoryId
LEFT OUTER JOIN Exempt
ON ComponentRuleSet.ExemptID = Exempt.ComponentExemptionID
WHERE (ComponentRuleSet.ComponentID = 38048)
The problem is that there are two fields in the ComponentRuleSet table called NormalType and Supertype. If either of those fields have a value, I need to display it in a column called Type. Yet, if neither have a value I need to display a Blank value in the Type column.
Any ideas?
---EDIT
Is my placement of COALESCE correct in the edited query? It is still returning errors.
--UPDATE
IMPORTANT: The type of both fields are boolean, I need to return the column name of the column that holds a TRUE value, and place that value in the TYPE column.
Use COALESCE for this field:
COALESCE(ComponentRuleSet.NormalType, ComponentRuleSet.Supertype, '') AS Type
COALESCE:
Returns the first nonnull expression among its arguments.
Following your comments as to the actual requirement, CASE is probably a better option:
CASE WHEN ComponentRuleSet.NormalType = 1 THEN 'NormalType'
WHEN ComponentRuleSet.Supertype = 1 THEN 'SuperType'
ELSE ''
END AS Type
Seeing your comments, perhaps a CASE expression will work:
select ...
, CASE WHEN ComponentRuleSet.NormalType is not null then 'NormalType'
WHEN ComponentRuleSet.Supertype is not null then 'SuperType'
ELSE ''
end as Type
UPDATE Since boolean values are just 1 for true and 0 for false, try this:
select ...
, CASE WHEN ComponentRuleSet.NormalType = 1 then 'NormalType'
WHEN ComponentRuleSet.Supertype = 1 then 'SuperType'
ELSE ''
end as Type

Changing stored procedure

I have a proc that print checks if there is any new checks to be print. If there is nothing to issue new checks it wont print any. Now i want to modify this proc like even if i don't have any new checks to be print, it should pick up at least one check to be print.( even if it is already printed). Can you tell me how to do that. Here is the stored proc.
CREATE PROCEDURE [proc_1250_SELCashiersChecksForPrint] AS
SELECT t_DATA_CashiersChecksIssued.ControlNbr,
t_DATA_CashiersChecksIssued.Audit_DateAdded,
t_DATA_CashiersChecksIssued.BatchNbr,
t_DATA_CashiersChecksIssued.SerialNbr,
t_DATA_CashiersChecksIssued.CheckRTN,
t_DATA_CashiersChecksIssued.CheckAccountNbr,
t_DATA_CashiersChecksIssued.Amount,
t_DATA_CashiersChecksIssued.DateIssued,
t_DATA_CashiersChecksIssued.Payee,
t_DATA_CashiersChecksIssued.Address,
t_DATA_CashiersChecksIssued.City,
t_DATA_CashiersChecksIssued.State,
t_DATA_CashiersChecksIssued.Zip,
t_DATA_Reclamation.ClaimId,
t_DATA_Reclamation.NoticeDate,
t_DATA_Reclamation.FirstName,
t_DATA_Reclamation.MiddleName,
t_DATA_Reclamation.LastName,
t_DATA_Reclamation.ClaimTotal,
t_PCD_Claimant.Name AS Agency,
t_DATA_CashiersChecksIssued.IDENTITYCOL
FROM t_DATA_CashiersChecksIssued INNER JOIN
t_DATA_Reclamation ON
t_DATA_CashiersChecksIssued.ControlNbr = t_DATA_Reclamation.ControlNbr
INNER JOIN
t_PCD_Claimant ON
t_DATA_Reclamation.ClaimantCode = t_PCD_Claimant.ClaimantCode
WHERE (t_DATA_CashiersChecksIssued.SerialNbr IS NULL) AND
(t_DATA_CashiersChecksIssued.DateIssued IS NULL)
ORDER BY t_DATA_CashiersChecksIssued.Audit_DateAdded ASC,
t_DATA_CashiersChecksIssued.ControlNbr ASC
Let me know if you need more information.
SELECT TOP 1 t_DATA_CashiersChecksIssued.ControlNbr,
t_DATA_CashiersChecksIssued.Audit_DateAdded,
t_DATA_CashiersChecksIssued.BatchNbr,
t_DATA_CashiersChecksIssued.SerialNbr,
t_DATA_CashiersChecksIssued.CheckRTN,
t_DATA_CashiersChecksIssued.CheckAccountNbr,
t_DATA_CashiersChecksIssued.Amount,
t_DATA_CashiersChecksIssued.DateIssued,
t_DATA_CashiersChecksIssued.Payee, t_DATA_CashiersChecksIssued.Address,
t_DATA_CashiersChecksIssued.City, t_DATA_CashiersChecksIssued.State,
t_DATA_CashiersChecksIssued.Zip, t_DATA_Reclamation.ClaimId,
t_DATA_Reclamation.NoticeDate, t_DATA_Reclamation.FirstName,
t_DATA_Reclamation.MiddleName, t_DATA_Reclamation.LastName,
t_DATA_Reclamation.ClaimTotal, t_PCD_Claimant.Name AS Agency,
t_DATA_CashiersChecksIssued.IDENTITYCOL
FROM t_DATA_CashiersChecksIssued
INNER JOIN t_DATA_Reclamation ON t_DATA_CashiersChecksIssued.ControlNbr = t_DATA_Reclamation.ControlNbr
INNER JOIN t_PCD_Claimant ON t_DATA_Reclamation.ClaimantCode = t_PCD_Claimant.ClaimantCode
ORDER BY t_DATA_CashiersChecksIssued.Audit_DateAdded DESC
Use the TOP n SQL syntax :
if EXISTS ( /* Look for an unprinted check - "date_issued is null" */ )
/* print unprinted checks */
ELSE
select top 1 /* already-printed-checks */
where .... "date_issued is not null"
OR
Do you want to print a "Voided/Cancelled" check - when you do that?
You have to decide how you want to pick your "at least one".
The simplest way (probably) is to remove whatever condition in the WHERE clause is excluding already printed checks. Let's assume that's t_DATA_CashiersChecksIssued.DateIssued IS NULL. Now add a column to your SELECT clause like this: CASE WHEN t_DATA_CashiersChecksIssued.DateIssued IS NULL then 0 ELSE 1 END and make that column first in your ORDER BY clause.
Now in the procedure, fetch just one row from this cursor. If this new column has the value 0, there's at least one new check to be processed and you should iterate through the cursor but stop when you get to an already issued one. If it has the value 1, there are no new checks.
Edit: The other approach would be to do it right in your SQL. Leave the original as is, but add a clause like:
UNION ALL SELECT ... AND ROWNUM = 1 where ... represents your existing query, but with the condition to exclude already printed checks removed. On second thought, this may be simpler.