SQL Multiple CASE statements return 0 instead of NULL - sql

I Have the following SQL Case statement which works perfectly as long as the Years match MF.Date & M.MemberCurrentYear. There will be scenarios where the years do not match and this returns a Balance of NULL. I would like it to return a Zero.
SELECT SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END) AS Balance
FROM dbo.MemberFinancials AS MF
INNER JOIN dbo.Members AS M ON MF.MemberID = M.MemberID
AND DATEPART(yyyy, MF.Date) = M.MemberCurrentYear
INNER JOIN dbo.FinancialTypes AS FT ON MF.FinancialTypeID = FT.FinancialTypeID
Thanks

SELECT
ISNULL(SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END),0) AS Balance
FROM dbo.MemberFinancials AS MF INNER JOIN
dbo.Members AS M ON MF.MemberID = M.MemberID AND DATEPART(yyyy, MF.Date) = M.MemberCurrentYear INNER JOIN
dbo.FinancialTypes AS FT ON MF.FinancialTypeID = FT.FinancialTypeID
Use ISNULL (Or COALESCE if you prefer...)

SELECT ISNULL( SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END), 0) AS Balance

SELECT
COALESCE(
SUM(CASE WHEN Type = 1 THEN Amount ELSE Amount * - 1 END)
, 0) AS Balance

Related

The SQL Server query is taking too long to load the data

The below query is actually a view which is being used to display the cash payment report. But it is taking too much of time to load the data
SELECT
Billing_AccountPaymentDate.DueDate,
SUM(Billing_AccountCharge.NetAmount) AS NetCharges,
ISNULL(SUM(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances + AccountChargePayment.SchoolRemittancesPending), 0) / SUM(Billing_AccountCharge.NetAmount) AS PercentCollected,
SUM(Billing_AccountCharge.NetAmount - ISNULL(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances + AccountChargePayment.SchoolRemittancesPending, 0)) AS RemainingBalance,
Billing_AccountPaymentDate.RemittanceEffectiveDate,
Billing_Account.SchoolId,
ISNULL(SUM(AccountChargePayment.SchoolPayments), 0) AS SchoolPayments,
ISNULL(SUM(AccountChargePayment.SchoolRemittances), 0) AS SchoolRemittances,
ISNULL(SUM(AccountChargePayment.SchoolRemittancesPending), 0) AS SchoolRemittancesPending,
Billing_Account.SchoolYearId,
ISNULL(SUM(AccountChargePayment.SchoolPayments + AccountChargePayment.SchoolRemittances), 0) AS TotalReceipts
FROM
Billing_AccountCharge
INNER JOIN
Billing_AccountInvoice ON
Billing_AccountInvoice.AccountInvoiceId = Billing_AccountCharge.AccountInvoiceId
INNER JOIN
Billing_Account ON
Billing_Account.AccountId = Billing_AccountInvoice.AccountId
INNER JOIN
Billing_PaymentMethod ON
Billing_PaymentMethod.PaymentMethodId = CASE WHEN Billing_AccountInvoice.AutomaticPaymentEligible = 1 THEN Billing_Account.PaymentMethodId ELSE 3 END -- Send Statements
INNER JOIN
Billing_AccountPaymentDate ON
Billing_AccountPaymentDate.AccountPaymentMethodId = Billing_PaymentMethod.AnticipatedAccountPaymentMethodId AND
Billing_AccountPaymentDate.DueDate = Billing_AccountInvoice.DueDate AND
Billing_AccountPaymentDate.HoldForFee = Billing_Account.HoldPaymentForFee
INNER JOIN
Billing_ChargeItem ON
Billing_ChargeItem.ChargeItemId = Billing_AccountCharge.ChargeItemId
LEFT OUTER JOIN
(
SELECT
Billing_AccountChargePayment.AccountChargeId,
SUM(CASE WHEN Billing_AccountPayment.AccountPaymentTypeId = 9 THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolPayments,
SUM(CASE WHEN Billing_AccountChargePayment.SchoolRemittanceId IS NOT NULL THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolRemittances,
SUM(CASE WHEN Billing_AccountChargePayment.SchoolRemittanceId IS NULL AND Billing_AccountPayment.AccountPaymentTypeId <> 9 THEN Billing_AccountChargePayment.Amount ELSE 0 END) AS SchoolRemittancesPending
FROM
Billing_AccountChargePayment
INNER JOIN
Billing_AccountPayment ON
Billing_AccountPayment.AccountPaymentId = Billing_AccountChargePayment.AccountPaymentId
GROUP BY
Billing_AccountChargePayment.AccountChargeId
) AccountChargePayment ON
AccountChargePayment.AccountChargeId = Billing_AccountCharge.AccountChargeId
WHERE
Billing_AccountInvoice.AccountInvoiceStatusId <> 4 AND -- Voided
Billing_ChargeItem.RemitToSchool = 1
AND Billing_Account.[SchoolId] = 6 --hard code in a school with data
AND Billing_Account.[SchoolYearId] = 12 --hard code in a school year with data
GROUP BY
Billing_AccountPaymentDate.DueDate,
Billing_AccountPaymentDate.RemittanceEffectiveDate,
Billing_Account.SchoolId,
Billing_Account.SchoolYearId
HAVING
SUM(Billing_AccountCharge.NetAmount) <> 0
order by Billing_AccountPaymentDate.DueDate ASC
It looks like the inner query in the left join is taking too much of time, both the tables already have non clustered index, I tried taking those tables outside but the data is not accurate
Use CTE instead of subquery and do all calculation there instead of in Left outer join. Moreover, use with(nolock) whenever you fetch data. Still your query is taking much more time then You should implement proper indexing.
WITH PaymentData AS (
SELECT
acp.AccountChargeId,
SUM(
CASE
WHEN ap.AccountPaymentTypeId = 9 THEN acp.Amount
ELSE 0
END
) AS SchoolPayments,
SUM(
CASE
WHEN acp.SchoolRemittanceId IS NOT NULL THEN acp.Amount
ELSE 0
END
) AS SchoolRemittances,
SUM(
CASE
WHEN acp.SchoolRemittanceId IS NULL AND ap.AccountPaymentTypeId <> 9 THEN acp.Amount
ELSE 0
END
) AS SchoolRemittancesPending
FROM
Billing_AccountChargePayment acp WITH(NOLOCK)
INNER JOIN Billing_AccountPayment ap WITH(NOLOCK) ON acp.AccountPaymentId = ap.AccountPaymentId
GROUP BY
acp.AccountChargeId
)
SELECT
apd.DueDate,
SUM(ac.NetAmount) AS NetCharges,
COALESCE(
SUM(pd.SchoolPayments + pd.SchoolRemittances + pd.SchoolRemittancesPending),
0
) / SUM(ac.NetAmount) AS PercentCollected,
SUM(ac.NetAmount - COALESCE(pd.SchoolPayments, 0) - COALESCE(pd.SchoolRemittances, 0) - COALESCE(pd.SchoolRemittancesPending, 0)) AS RemainingBalance,
apd.RemittanceEffectiveDate,
a.SchoolId,
COALESCE(SUM(pd.SchoolPayments), 0) AS SchoolPayments,
COALESCE(SUM(pd.SchoolRemittances), 0) AS SchoolRemittances,
COALESCE(SUM(pd.SchoolRemittancesPending), 0) AS SchoolRemittancesPending,
a.SchoolYearId,
COALESCE(SUM(pd.SchoolPayments + pd.SchoolRemittances), 0) AS TotalReceipts
FROM
Billing_AccountCharge ac WITH(NOLOCK)
INNER JOIN Billing_AccountInvoice ai WITH(NOLOCK) ON ac.AccountInvoiceId = ai.AccountInvoiceId
INNER JOIN Billing_Account a WITH(NOLOCK) ON ai.AccountId = a.AccountId
INNER JOIN Billing_PaymentMethod pm WITH(NOLOCK) ON pm.PaymentMethodId = CASE
WHEN ai.AutomaticPaymentEligible = 1 THEN a.PaymentMethodId
ELSE 3
END
INNER JOIN Billing_AccountPaymentDate apd WITH(NOLOCK) ON
apd.AccountPaymentMethodId = pm.AnticipatedAccountPaymentMethodId AND
apd.DueDate = ai.DueDate AND
apd.HoldForFee = a.HoldPaymentForFee
INNER JOIN Billing_ChargeItem ci WITH(NOLOCK) ON ac.ChargeItemId = ci.ChargeItemId
LEFT OUTER JOIN PaymentData pd WITH(NOLOCK) ON ac.AccountChargeId = pd.AccountChargeId
WHERE
ai.AccountInvoiceStatusId <> 4 AND
ci.RemitToSchool = 1 AND
a.SchoolId = 6 AND
a.SchoolYearId = 12
GROUP BY
apd.DueDate,
apd.RemittanceEffectiveDate,
a.SchoolId,
a.SchoolYearId
HAVING
SUM(ac.NetAmount) <> 0
ORDER BY
apd.DueDate ASC;

using Query one results to run Query two

SELECT distinct
Pd.Cpd as ' accountnumber'
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
This code would result with this
Result
accountnumber
1332132
3213123
5641202
6412221
1233242
What I would like to do is when the code above gets the results my bottom code reads them and runs them trough its code. The common denominator here would be the account number because its running through a different table
SELECT
pm.AcctNumb as 'accountnumber'
, SUM(CASE WHEN pm.cusidIN ('cr') THEN 1 ELSE 0 END) AS CA
, SUM(CASE WHEN pm.cusidIN ('gb') THEN 1 ELSE 0 END) AS GB
, SUM(CASE WHEN pm.cusidIN ('tev','offev','Lastev') THEN 1 ELSE 0 END) AS chr
, SUM(CASE WHEN pm.cusidIN
('pm','pr','che' )
THEN 1 ELSE 0 END) AS Act
, SUM(CASE WHEN pm.cusidIN ('supev','tev') THEN 1 ELSE 0 END) AS Fulfillment
FROM ops.medadata pm WITH (NOLOCK)
INNER JOIN mw.pim_acct Ma with (nolock) ON ma.AcctNumb= pm.AcctNumb
Where pm.AcctNumb in ()
GROUP BY
pm.AcctNumb
I have tried doing this the code below but it doesnt seem to work
With counta as (
SELECT distinct
Pd.Cpd as ' accountnumber'
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
SELECT
pm.AcctNumb as 'accountnumber'
, SUM(CASE WHEN pm.cusidIN ('cr') THEN 1 ELSE 0 END) AS CA
, SUM(CASE WHEN pm.cusidIN ('gb') THEN 1 ELSE 0 END) AS GB
, SUM(CASE WHEN pm.cusidIN ('tev','offev','Lastev') THEN 1 ELSE 0 END) AS chr
, SUM(CASE WHEN pm.cusidIN
('pm','pr','che' )
THEN 1 ELSE 0 END) AS Act
, SUM(CASE WHEN pm.cusidIN ('supev','tev') THEN 1 ELSE 0 END) AS Fulfillment
FROM ops.medadata pm WITH (NOLOCK)
INNER JOIN mw.pim_acct Ma with (nolock) ON ma.AcctNumb= pm.AcctNumb
left join counta on Pm.accountnumber = counta.accountnumber
Where pm.AcctNumb in (counta.accountnumber)
GROUP BY
pm.AcctNumb
**im having issue with joining the two tables together**
IN is not an equivalent to a join - but you are treating that way.
Instead think of "IN this LIST" and the list could be supplied by you, or by a subquery e.g.
a list given by the query itself
select * from atable
where acol IN ('a','b','c') -- i.e. the list is hardcoded
or, using a subquery
SELECT ...etc.
WHERE pm.AcctNumb IN (
SELECT Pd.Cpd
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
or, if using a CTE
With counta as (
SELECT Pd.Cpd
FROM [RQL_ALK_PMT].[Cts_opps] pd
INNER JOIN [RQL_ALK_PMT].[Cts_opps].dpo.cnms_id metg on metg.cnms_id=me.cnms_id
)
SELECT ... etc.
WHERE pm.AcctNumb IN (
SELECT Cpd
FROM counta
)
note, it usually is not more efficient to use select distinct when forming a subquery to be used with an IN list.

Summing two seperate queries into one value using UNION ALL clause

I have the following query (as part of a larger query). I am trying to get the sum results from 2 different data sets within a subquery but I am having trouble trying to encapsulate the two into 1 value. What I have is this:
(Select SUM('Invoiced MTD') from
((Select SUM(CASE WHEN SOH.LASDLVNUM_0 <> '' AND SOH.LASINVNUM_0 <> '' AND MONTH(SOH.SHIDAT_0) = MONTH(GETDATE()) THEN
(SOP.NETPRI_0 * SOQ.QTY_0 * SOH.CHGRAT_0) ELSE 0 END) as 'Invoiced MTD'
From x3v6.CICPROD.SORDER SOH
LEFT OUTER JOIN x3v6.CICPROD.BPCUSTOMER BPC on SOH.BPCORD_0 = BPC.BPCNUM_0
LEFT OUTER JOIN x3v6.CICPROD.SORDERQ SOQ on SOH.SOHNUM_0 = SOQ.SOHNUM_0
LEFT OUTER JOIN x3v6.CICPROD.SORDERP SOP on SOQ.SOHNUM_0 = SOP.SOHNUM_0 and SOQ.SOPLIN_0 = SOP.SOPLIN_0 and SOQ.SOQSEQ_0 = SOP.SOPSEQ_0
LEFT OUTER JOIN x3v6.CICPROD.ITMMASTER ITM on SOP.ITMREF_0 = ITM.ITMREF_0 ))
UNION ALL
((Select SUM(CASE WHEN SIH.INVTYP_0 = 2 and MONTH(SIH.ACCDAT_0) = MONTH(GETDATE()) THEN SID.AMTNOTLIN_0 * (-1) ELSE 0 END) as 'Invoiced MTD'
From x3v6.CICPROD.SINVOICE SIH
Left Outer Join x3v6.CICPROD.SINVOICED SID on SIH.NUM_0 = SID.NUM_0))
as 'T2',
But I am getting an error where the UNION ALL clauses is, and I can't figure it out. Basically I want to combine Sales credit memos with the sales order dollar totals from a seperate table.
Can anyone assist me with this?
What about this ?
Select SUM([Invoiced MTD]) from
(
Select SUM(CASE WHEN SOH.LASDLVNUM_0 <> '' AND SOH.LASINVNUM_0 <> '' AND MONTH(SOH.SHIDAT_0) = MONTH(GETDATE())
THEN (SOP.NETPRI_0 * SOQ.QTY_0 * SOH.CHGRAT_0) ELSE 0 END) as 'Invoiced MTD'
From x3v6.CICPROD.SORDER SOH
LEFT OUTER JOIN x3v6.CICPROD.BPCUSTOMER BPC on SOH.BPCORD_0 = BPC.BPCNUM_0
LEFT OUTER JOIN x3v6.CICPROD.SORDERQ SOQ on SOH.SOHNUM_0 = SOQ.SOHNUM_0
LEFT OUTER JOIN x3v6.CICPROD.SORDERP SOP on SOQ.SOHNUM_0 = SOP.SOHNUM_0 and SOQ.SOPLIN_0 = SOP.SOPLIN_0 and SOQ.SOQSEQ_0 = SOP.SOPSEQ_0
LEFT OUTER JOIN x3v6.CICPROD.ITMMASTER ITM on SOP.ITMREF_0 = ITM.ITMREF_0
UNION ALL
Select SUM(CASE WHEN SIH.INVTYP_0 = 2 and MONTH(SIH.ACCDAT_0) = MONTH(GETDATE())
THEN SID.AMTNOTLIN_0 * (-1) ELSE 0 END) as 'Invoiced MTD'
From x3v6.CICPROD.SINVOICE SIH
Left Outer Join x3v6.CICPROD.SINVOICED SID on SIH.NUM_0 = SID.NUM_0
)T
Does this work? I'm not sure exactly what is causing your issue, but you definitely don't need so many parenthesis. I would also recommend using something that formats/ beautifies your SQL. It's a great way to 1) keep your code looking consistent and 2) flesh out syntax errors.
SELECT SUM(x.invoiced_mtd)
FROM (SELECT SUM(CASE
WHEN soh.lasdlvnum_0 <> '' AND soh.lasinvnum_0 <> '' AND
MONTH(soh.shidat_0) = MONTH(getdate()) THEN
(sop.netpri_0 * soq.qty_0 * soh.chgrat_0)
ELSE
0
END) AS invoiced_mtd
FROM x3v6.cicprod.sorder soh
LEFT OUTER JOIN x3v6.cicprod.bpcustomer bpc
ON soh.bpcord_0 = bpc.bpcnum_0
LEFT OUTER JOIN x3v6.cicprod.sorderq soq
ON soh.sohnum_0 = soq.sohnum_0
LEFT OUTER JOIN x3v6.cicprod.sorderp sop
ON soq.sohnum_0 = sop.sohnum_0
AND soq.soplin_0 = sop.soplin_0
AND soq.soqseq_0 = sop.sopseq_0
LEFT OUTER JOIN x3v6.cicprod.itmmaster itm
ON sop.itmref_0 = itm.itmref_0
UNION ALL
SELECT SUM(CASE
WHEN sih.invtyp_0 = 2 AND
MONTH(sih.accdat_0) = MONTH(getdate()) THEN
sid.amtnotlin_0 * (-1)
ELSE
0
END)
FROM x3v6.cicprod.sinvoice sih
LEFT OUTER JOIN x3v6.cicprod.sinvoiced sid
ON sih.num_0 = sid.num_0) x;
Try using a CTE for the UNION query first. Here is a simplified example with the same structure as your query:
;with cteTest AS (
((select 2 as 'test'))
union all
((select 3 as 'test'))
)
select sum(test) from cteTest

SQL QUERY with subquery Optimization

how can i optimize these query
SELECT
mp.ProviderName
,(SELECT count(mc.ClaimSubmissionID) FROM dbo.MST_Claim mc WHERE mc.HeaderID=mpach.HeaderID AND mc.IsActive=1) AS total_claim
,(SELECT count(mc.ClaimSubmissionID) FROM dbo.MST_Claim mc WHERE mc.HeaderID=mpach.HeaderID AND mc.op=1) AS total_op
,(SELECT count(mc.ClaimSubmissionID) FROM dbo.MST_Claim mc WHERE mc.HeaderID=mpach.HeaderID AND mc.ip=1) AS total_ip
FROM dbo.MST_PriorAuthorization_Claim_Header mpach
INNER JOIN dbo.MS_Provider mp ON mp.Provider_ID = mpach.Provider_ID
Use Sum of CASE Statements to avoid all those subqueries.
SELECT
mp.ProviderName,
SUM(CASE WHEN mc.IsActive=1 THEN 1 ELSE 0 END ) AS total_claim,
SUM(CASE WHEN mc.op=1 THEN 1 ELSE 0 END ) AS total_op,
SUM(CASE WHEN mc.ip=1 THEN 1 ELSE 0 END ) AS total_ip
FROM dbo.MST_PriorAuthorization_Claim_Header mpach
INNER JOIN dbo.MS_Provider mp ON mp.Provider_ID = mpach.Provider_ID
INNER JOIN dbo.MST_Claim mc ON mc.HeaderID=mpach.HeaderID
You can modify your query using a CASE statement like below
SELECT
mp.ProviderName
,sum(case when mc.IsActive=1 then mc.ClaimSubmissionID else 0 end) AS total_claim,
sum(case when mc.op=1 then mc.ClaimSubmissionID else 0 end) AS total_op
sum(case when mc.ip=1 then mc.ClaimSubmissionID else 0 end) AS total_ip
FROM dbo.MST_PriorAuthorization_Claim_Header mpach
INNER JOIN dbo.MS_Provider mp ON mp.Provider_ID = mpach.Provider_ID
JOIN dbo.MST_Claim mc ON mc.HeaderID = mpach.HeaderID;

Not able to Group table on percentage Column

Edit : Database - SQL server 2014
I am trying to Calculate Daily Percentage Of Student "Present" like this :
But I Getting Result like this :
Only while Calculating Percentage I am not able to group Rows based on Class.
With Out percentage Calculation , Result are grouping Fine
My Student Attendance table..
This is My Query...
SELECT CM.ClassName ,SB.SubjectName ,
count(sa.Day14) Total,
sum(case when sa.Day14 = 'P' then 1 else 0 end) Present,
sum(case when sa.Day14 = 'A' then 1 else 0 end) Absent,
(SELECT CAST(
CASE
WHEN count(sa.Day14) = 0
THEN 0
ELSE (sum(case when Day14 = 'P' then 1 else 0 end)* 100)/(count(Day14))
END AS nvarchar(100))) as [Present%],
AttendanceDate from studentattendance SA
inner join studentmaster SM on SA.StudentID = SM.ID
join ProfessorMaster p on SA.ProfessorID = p.Id
join Classmaster CM on SA.ClassID = CM.ID
inner join SubjectMaster SB on SA.SubjectID = SB.ID
where
sa.ProfessorID = '36' and sa.AttendanceDate = '2015-09' and SA.AdminId ='29'
group by CM.ClassName, SB.SubjectName, SA.AttendanceDate,sa.Day14
What I am Missing ?
The problem with your query is that you are doing a count on Day14 group by Day14. With this you can't do sum in the same query as you specified a group by already. So you have to split your query.
Lets say your attendance table looks like this for a particular subject/class on a particular day.
StudentID Day14
46 A
47 P
48 P
If you are using Oracle,then create a CTE. Else create a view to count 'A' and 'P'.
select distinct(Day14), count(*) as AorP from yourTable group by Day14
Now create another CTE/view to get the total sum and percent like below
select DAY14, AORP*100/(select sum(AORP) as yourView from tbl2) as percentage from tbl2
This will give you result like
Day14 PERCENTAGE
P 66.67
A 33.33
Now join this view to your main query to get PERCENTAGE based for Present or Absent. You can also use this view as an inline query (like
select col1,(select Day14 as AbsentPercent from newView where id=something and Day14='A')
Note: This view is just for example, You have to add at least 1 unique identifier to join to your main table later. To capture missing entries, use appropriate outer join.
I got much Smaller Solution :) ...
Calculate Percentage in Datatable[Or any ResultSet in Code] ...
My Query (Not calculating Percentage )
SELECT CM.ClassName ,SB.SubjectName ,
count(sa.Day14) Total,
sum(case when sa.Day14 = 'P' then 1 else 0 end) Present,
sum(case when sa.Day14 = 'A' then 1 else 0 end) Absent,
'' [Present%] ,
AttendanceDate from studentattendance SA
inner join studentmaster SM on SA.StudentID = SM.ID
join ProfessorMaster p on SA.ProfessorID = p.Id
join Classmaster CM on SA.ClassID = CM.ID
inner join SubjectMaster SB on SA.SubjectID = SB.ID
where
sa.ProfessorID = '36' and sa.AttendanceDate = '2015-09' and SA.AdminId ='29'
group by CM.ClassName, SB.SubjectName, SA.AttendanceDate,sa.Day14
and in DataTable ......
foreach (DataRow dr in ds.Tables[0].Rows)
{
var Total = Convert.ToInt32(Convert.ToDouble(dr["Total"]));
var Present = Convert.ToInt32(Convert.ToDouble(dr["Present"]));
dr["Present%"] = (Present * 100) / Total;
}