SQL sum() not adding up correctly - sql

I have the following Temp table and Insert statement:
declare #ClaimNumbers table (ClaimId Id_t, ClaimNumber RefNumber_t, AmtPaid Money_t, RecordStatus Code_t null, Amount Money_t null, ProcessingStatus code_t null)
insert into #ClaimNumbers
(
ClaimNumber,
ClaimId,
AmtPaid,
RecordStatus,
Amount,
ProcessingStatus
)
select
E.ReferenceNumber,
E.ClaimId,
sum(E.AmtPaid),
CBR.RecordStatus,
sum(CBR.Amount),
C.ProcessingStatus
from EDIXacts E
left join ClaimBillingRecords CBR
on CBR.ClaimId = E.ClaimId
and CBR.BillingEntityMapId in (select BillingEntityMapId from BillingEntityMap where BillingEntityId = 255) --#BillingEntityId)
and CBR.RecordStatus = 'POS'
left join Claims C on C.ClaimId = E.ClaimId
where E.CheckId = 1747 --#CheckId
and XactType = 'RMT'
and XactStatus in ('NRM','SLM')
group by E.ReferenceNumber,
E.ClaimId,
CBR.RecordStatus,
C.ProcessingStatus
Given example data:
ClaimBillingRecords
ClaimId,RecordStatus,Amount
3807,'POS',-100
3807,'POS',120
EDIXacts
XactType,XactStatus,CheckId,AmtPaid
'RMT','NRM',1747,-100
'RMT','SLM',1747,120
I am expecting the Amount to be $20 and the AmtPaid to be $20, however I am getting Amount: $40 and AmtPaid: $40.
Is there something I am doing wrong with the aggregate function?

Without having complete table structures with valid sample data it's hard to tell what's wrong. My guess is your rows are being multiplied through joining. Please check below select query to check the data first then use group by to sum those.
declare #ClaimNumbers table (ClaimId Id_t, ClaimNumber RefNumber_t, AmtPaid Money_t, RecordStatus Code_t null, Amount Money_t null, ProcessingStatus code_t null)
insert into #ClaimNumbers
(
ClaimNumber,
ClaimId,
AmtPaid,
RecordStatus,
Amount,
ProcessingStatus
)
select
E.ReferenceNumber,
E.ClaimId,
sum(E.AmtPaid),
CBR.RecordStatus,
sum(CBR.Amount),
C.ProcessingStatus
from EDIXacts E
left join ClaimBillingRecords CBR
on CBR.ClaimId = E.ClaimId
and CBR.BillingEntityMapId in (select BillingEntityMapId from BillingEntityMap where BillingEntityId = 255) --#BillingEntityId)
and CBR.RecordStatus = 'POS'
left join Claims C on C.ClaimId = E.ClaimId
where E.CheckId = 1747 --#CheckId
and XactType = 'RMT'
and XactStatus in ('NRM','SLM')
Hope you will get the idea why Amount and AmountPaid column is having double the expected amount.

Related

How can I had multiple values to a variable or an Array

I have a working query below. however I need to make OWNRSHP_ID a variable that I can supply a list of OWNRSHP_IDs to be ran through the query one by one.
The idea is to have a variable that I can supply a list of ID and the query will run through each one one by one.
This SQL that I'm currently running in Teradata.
Select distinct
inv_corp.OWNRSHP_ID
,SE.Sending_entity_nm AS Bottler
,snap.FSH_DSTR_OWNRSHP_ID AS DELIVERY_SOURCE
,inv_corp.BTLR_DLVR_PNT_NO AS BTLR_DLVR_PNT_NO
,snap.DLVR_PNT_NM AS BTLR_DLVR_PNT_NM
,snap.CHNL_TYPE_DESC AS MARKET_TYPE
,snap.TRADE_CHNL_DESC AS TRADE_CHNL_DESC
,snap.TCCC_SUB_CHNL_NM AS TCCC_SUB_CHNL_NM
,snap.STATE AS STATE
,CASE
WHEN cbs.CBS_BUSINESS_TYPE = 1 THEN 'TRADE SALE'
WHEN cbs.CBS_BUSINESS_TYPE = 4 THEN 'FULL SERVE'
WHEN cbs.CBS_BUSINESS_TYPE = 5 THEN 'EXTRNL SLS'
ELSE NULL
END AS CBS_BUSINESS_TYPE
,ptype.PRD_TYP_NM AS PROD_TYPE
,cal.CUR_YR_AC_PRD AS CAL_YEAR_MONTH
--,cal.CUR_YR_AC_PRD AS CAL_YEAR_MONTH
,inv_corp.Inv_dt
,sum(CASE
WHEN (qty) IS NOT NULL THEN (qty* TCCC_192CONV(FLOAT))
ELSE 0
END )AS VolEQ --20 fields
,sum(CASE
WHEN (qty) IS NOT NULL THEN (cast(qty as FLOAT )* cast(prodet.STD_ADJ_FCT as FLOAT))
ELSE 0
END) AS VolStd
,(sum(Whlsl_Price_Xtnd) - sum(Off_Inv_Cma_Disc)) - (sum(Off_Inv_Ctm_Disc) - sum(On_Inv_Disc) ) as DNSI
FROM CORP_LINES_VIEWS.LINE_CORP line_corp
join corp_invoice_VIEWS.invoice_corp inv_corp
On line_corp.Tsr_Inv_Ref_No = inv_corp.Tsr_Inv_Ref_No
and line_corp.OWNRSHP_ID = inv_corp.OWNRSHP_ID
Join CBS_VIEWS.CBS_DELIVERY_POINT cbs
ON inv_corp.BTLR_DLVR_PNT_NO = cbs.BTLR_DLVR_PNT_NO
and inv_corp.OWNRSHP_ID = cbs.OWNRSHP_ID
Join CHR_VIEWS.DPT_SNAPSHOT_SELECT snap
ON inv_corp.BTLR_DLVR_PNT_NO = snap.BTLR_DLVR_PNT_NO
and inv_corp.OWNRSHP_ID = snap.OWNRSHP_ID
Join CBS_VIEWS.sending_entity se
ON inv_corp.OWNRSHP_ID = se.OWNRSHP_ID
Join NSR_VIEWS.PRODET prodet
ON prodet.cce_material_no = line_corp.cce_material_no
Join DLCCC_CUST_CNTC_CNTR_LAB.TBL_3PY_to_YTD_CAL cal
ON CAL.fact_dt = line_corp.Inv_dt
Join CORP_LINES.MATL_JOIN_KEY mkey
ON mkey.cce_material_no = line_corp.cce_material_no
and mkey.OWNRSHP_ID = line_corp.OWNRSHP_ID
Join IWR_VIEWS.MN_PROD_TYPE ptype
ON ptype.tsr_prd_typ = prodet.tsr_prd_typ
Where 1=1
and line_corp.inv_dt>'2018-01-01'
and line_corp.OWNRSHP_ID IN (10,55,75,110,65,85,95)
GROUP BY
inv_corp.OWNRSHP_ID
,SE.Sending_entity_nm
,snap.FSH_DSTR_OWNRSHP_ID
,inv_corp.BTLR_DLVR_PNT_NO
,snap.DLVR_PNT_NM
,snap.CHNL_TYPE_DESC
,snap.TRADE_CHNL_DESC
,snap.TCCC_SUB_CHNL_NM
,snap.STATE
,cbs.CBS_BUSINESS_TYPE
,ptype.PRD_TYP_NM
,cal.CUR_YR_AC_PRD
,inv_corp.Inv_dt
Well, you currently do supply a list of OWNRSHP_IDs in
and line_corp.OWNRSHP_ID IN (10,55,75,110,65,85,95)
But assuming you want to pass this list as a comma-separated string you can apply STRTOK_SPLI_TO_TABLE
and line_corp.OWNRSHP_ID IN
(
SELECT Cast(token AS INT) AS OWNRSHP_ID, tokennum
FROM TABLE (StrTok_Split_To_Table(1, :OWNRSHP_IDs, ',')
RETURNS (outkey INTEGER,
tokennum INTEGER,
token VARCHAR(20) CHARACTER SET Unicode)
) AS d
)
If you move this into a Derived Table you can even order by the position of the id within the input string:
...
Join IWR_VIEWS.MN_PROD_TYPE ptype
ON ptype.tsr_prd_typ = prodet.tsr_prd_typ
JOIN
(
SELECT Cast(token AS INT) AS OWNRSHP_ID, tokennum
FROM TABLE (StrTok_Split_To_Table(1, :OWNRSHP_IDs, ',')
RETURNS (outkey INTEGER,
tokennum INTEGER,
token VARCHAR(20) CHARACTER SET Unicode)
) AS d
) as dt
ON inv_corp.OWNRSHP_ID = dt.OWNRSHP_ID
...
ORDER BY tokennum;
And when you Outer Join to the Derived Table you can also return a NULL row for a missing ID, but this probably needs some additional changes to your query.

I want you to help me prepare a detailed customer statement report

The purpose of the report is to provide a detailed account of the customer showing the balance after each transaction between two dates and balance before the start date
I have a view from three tables in SQL Server. I want to extract the evidence from it on three basis dates beginning and end date. However, the previous balance is displayed on the client at the beginning of the report. How can this be done knowing that there is no balance column in the view .
I use stored procedures
I want the report outputs to be like this
I use this code but I have problem
declare #id_customer int
;with initial as(
select *
from result
where id_customer= #id_customer
),report as(
select r.id,[balance]=isnull((select sum(b.debit-b.credit)
from initial b
where b.[date]<r.[date]) + r.debit - r.credit ,r.debit-r.credit)
from initial r
)
select [Operation type] = type,
reference_no = r.id,
[description],
[Debit] = debit,
[Credit] = credit,
[Balance] = b.balance
from result r
inner join report b on b.id = r.id
where r.id_customer = #id_customer
order by r.[date]
some records come towc
picture
Try this one, it's hard to guess without example data, but should work.
I assumed that transaction ID is incremental, so correct me if I'm wrong:
declare #id_customer int = 2
;with initial as(
select *
from result
where id_customer= #id_customer
),report as(
select r.id,[balance]=isnull((select sum(b.debit-b.credit)
from initial b
where b.[date]<=r.[date] and b.[id]<r.[id] ) +
r.debit - r.credit ,r.debit-r.credit),r.date
from initial r
)
select [Operation type] = r.type,
reference_no = r.id,
[description] = r.description,
[Debit] = r.debit,
[Credit] = r.credit,
[Balance] = b.balance,
[Date] = r.date
from result r
inner join report b on b.id = r.id
where r.id_customer = #id_customer
group by r.id, r.type,r.debit,r.credit,r.date,r.description,b.balance
order by r.[date]

SQL Server / T-SQL : query optimization assistance

I have this QA logic that looks for errors into every AuditID within a RoomID to see if their AuditType were never marked Complete or if they have two complete statuses. Finally, it picks only the maximum AuditDate of the RoomIDs with errors to avoid showing multiple instances of the same RoomID, since there are many audits per room.
The issue is that the AUDIT table is very large and takes a long time to run. I was wondering if there is anyway to reach the same result faster.
Thank you in advance !
IF object_ID('tempdb..#AUDIT') is not null drop table #AUDIT
IF object_ID('tempdb..#ROOMS') is not null drop table #ROOMS
IF object_ID('tempdb..#COMPLETE') is not null drop table #COMPLETE
IF object_ID('tempdb..#FINALE') is not null drop table #FINALE
SELECT distinct
oc.HotelID, o.RoomID
INTO #ROOMS
FROM dbo.[rooms] o
LEFT OUTER JOIN dbo.[hotels] oc on o.HotelID = oc.HotelID
WHERE
o.[status] = '2'
AND o.orderType = '2'
SELECT
t.AuditID, t.RoomID, t.AuditDate, t.AuditType
INTO
#AUDIT
FROM
[dbo].[AUDIT] t
WHERE
t.RoomID IN (SELECT RoomID FROM #ROOMS)
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
SELECT
o.HotelID, o.RoomID,
a.AuditID, a.RoomID, a.AuditDate, a.AuditType, a.CompleteStatus,
c.ClientNum
INTO
#FINALE
FROM
#ROOMS O
LEFT OUTER JOIN
#COMPLETE a on o.RoomID = a.RoomID
LEFT OUTER JOIN
[dbo].[clients] c on o.clientNum = c.clientNum
SELECT
t.*,
Complete_Error_Status = CASE WHEN t.CompleteStatus = 0
THEN 'Not Complete'
WHEN t.CompleteStatus > 1
THEN 'Complete More Than Once'
END
FROM
#FINALE t
INNER JOIN
(SELECT
RoomID, MAX(AuditDate) AS MaxDate
FROM
#FINALE
GROUP BY
RoomID) tm ON t.RoomID = tm.RoomID AND t.AuditDate = tm.MaxDate
One section you could improve would be this one. See the inline comments.
SELECT
t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO
#COMPLETE
FROM
(SELECT
RoomID,
COUNT(1) AS CompleteStatus
-- Use the above along with the WHERE clause below
-- so that you are aggregating fewer records and
-- avoiding a CASE statement. Remove this next line.
--SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
FROM
#AUDIT
WHERE
AuditType = 'Complete'
GROUP BY
RoomID) t1
INNER JOIN
#AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
t1.CompleteStatus = 0
OR t1.CompleteStatus > 1
Just a thought. Streamline your code and your solution. you are not effectively filtering your datasets smaller so you continue to query the entire tables which is taking a lot of your resources and your temp tables are becoming full copies of those columns without the indexes (PK, FK, ++??) on the original table to take advantage of. This by no means is a perfect solution but it is an idea of how you can consolidate your logic and reduce your overall data set. Give it a try and see if it performs better for you.
Note this will return the last audit record for any room that has either not had an audit completed or completed more than once.
;WITH cte AS (
SELECT
o.RoomId
,o.clientNum
,a.AuditId
,a.AuditDate
,a.AuditType
,NumOfAuditsComplete = SUM(CASE WHEN a.AuditType = 'Complete' THEN 1 ELSE 0 END) OVER (PARTITION BY o.RoomId)
,RowNum = ROW_NUMBER() OVER (PARTITION BY o.RoomId ORDER BY a.AuditDate DESC)
FROm
dbo.Rooms o
LEFT JOIN dbo.Audit a
ON o.RoomId = a.RoomId
WHERE
o.[Status] = 2
AND o.OrderType = 2
)
SELECT
oc.HotelId
,cte.RoomId
,cte.AuditId
,cte.AuditDate
,cte.AuditType
,cte.NumOfAuditsComplete
,cte.clientNum
,Complete_Error_Status = CASE WHEN cte.NumOfAuditsComplete > 1 THEN 'Complete More Than Once' ELSE 'Not Complete' END
FROM
cte
LEFT JOIN dbo.Hotels oc
ON cte.HotelId = oc.HotelId
LEFT JOIN dbo.clients c
ON cte.clientNum = c.clientNum
WHERE
cte.RowNum = 1
AND cte.NumOfAuditsComplete != 1
Also note I changed your
WHERE
o.[status] = '2'
AND o.orderType = '2'
TO
WHERE
o.[status] = 2
AND o.orderType = 2
to be numeric without the single quotes. If the data type is truely varchar add them back but when you query a numeric column as a varchar it will do data conversion and may not take advantage of indexes that you have built on the table.

Exclude few selected fields on group by

I had a query that was returning member transaction information. This query has an aggregate function to calculate the amount. All is working fine according to its grouping. Now what I need to do is to add two more columns from different tables. I did try to add them unfortunately they are giving me duplicated information with tons number of records.
Can anyone help me I just want to be able to include the two fields on the query and not include them in the group by clause. And also ensure that data returned is not a duplicate
See below is the query I used.
DECLARE #LastMonthExtractID Int = 11
SELECT x.*
,lstmnth.Submission ---added
,lm_subt.SubmissionTypeDescription ---added
FROM (
SELECT MemberRef --unique key
, SiteName
, ChargePeriod
, SUM(Amount) AS Amount
, TransactionMap
, PackageCode
FROM (
SELECT MemberRef
, SiteName
, ChargePeriod
, Amount
, PackageCode
, CASE WHEN map.TransactionMap = 'JoinFee' AND lstmnth.ChargeDate <> lstmnth.JoinDate THEN 'PayPlan'
WHEN map.TransactionMap = 'MemberFee' AND lstmnth.PackageCode LIKE 'PV%' AND lstmnth.SiteID <> 15 THEN 'VitalityMF' -- must use Package and not CURRENT PACKAGE
WHEN map.TransactionMap = 'MemberFee' AND lstmnth.PackageCode LIKE 'PV%' AND lstmnth.SiteID = 15 THEN 'PlatVitalityMF' -- PLATINUM
WHEN map.TransactionMap = 'MemberFee' AND lstmnth.PackageCode LIKE 'Z%' THEN 'ZContract'
WHEN map.TransactionMap IS NULL THEN 'Other'
ELSE map.TransactionMap END AS TransactionMap
--, lstmnth.Submission
--, lm_subt.SubmissionTypeDescription --added
FROM dbo.CCX_Billing lstmnth
LEFT JOIN dbo.TransactionMap map on lstmnth.TransactionType = map.TransactionType
AND lstmnth.TransactionDescription = map.TransactionDescription
AND ISNULL (lstmnth.AnalysisCode, '') = map.AnalysisCode
WHERE lstmnth.ExtractID = #LastMonthExtractID
) l
GROUP BY SiteName, MemberRef, ChargePeriod, PackageCode, TransactionMap
) x
INNER JOIN dbo.CCX_Billing lstmnth ON lstmnth.MemberRef = x.MemberRef
LEFT JOIN dbo.CCX_Billing_PSubmission lm_sub on lstmnth.SubmissionID = lm_sub.ID
INNER JOIN dbo.CCX_Billing_SubmissionType lm_subt on lm_sub.SubmissionTypeID = lm_subt.SubmissionID --added

Showing all values in Group By with inclusion of CASE

I have the following data
CREATE TABLE #Test
(
Severity NVARCHAR(50)
,WorkId INT
)
INSERT INTO #Test VALUES('High',1)
INSERT INTO #Test VALUES('Critical',2)
SELECT
CASE
WHEN Severity IN ('High','Critical') THEN 'Critical'
WHEN Severity IN ('Low','Medium') THEN 'Medium'
END AS 'Severity'
,COUNT(*) AS 'Total'
FROM #Test
GROUP BY
CASE
WHEN Severity IN ('High','Critical') THEN 'Critical'
WHEN Severity IN ('Low','Medium') THEN 'Medium'
END
This results in output -
Severity | Total
---------+-------
Critical | 2
I am expecting the following output -
Severity | Total
---------+-------
Critical | 2
Medium | 0
I have looked into the following two links which details a similar case but not same and am still unable to get the result -
http://ask.sqlservercentral.com/questions/47705/showing-null-values-as-well-in-group-by-in-sql.html
How to return empty groups in SQL GROUP BY clause
Any help or links?
Further update.
Having tried the solution below, the results are still not appearing. Pasting here the actual code wherein I would need to apply the logic
SELECT s.NewSeverity AS 'Severity'
,COUNT(WI.microsoft_vsts_common_severity) AS 'Total'
FROM ( VALUES
('Critical','I-High')
,('High','I-High')
,('Medium','I-Low')
,('Low','I-Low')
)s(OldSeverity,NewSeverity)
LEFT JOIN DimWorkItem WI (NOLOCK)
ON WI.microsoft_vsts_common_severity = s.OldSeverity
JOIN dbo.DimPerson P
ON p.personsk = WI.system_assignedto__personsk
JOIN DimTeamProject TP
ON WI.TeamProjectSK = TP.ProjectNodeSK
JOIN DimIteration Itr (NOLOCK)
ON Itr.IterationSK = WI.IterationSK
JOIN DimArea Ar (NOLOCK)
ON Ar.AreaSK = WI.AreaSK
WHERE TP.ProjectNodeName = 'ABC'
AND WI.System_WorkItemType = 'Bug'
AND WI.Microsoft_VSTS_CMMI_RootCause <> 'Change Request'
AND Itr.IterationPath LIKE '%\ABC\R1234\Test\IT%'
AND WI.System_State NOT IN ( 'Rejected', 'Closed' )
AND WI.System_RevisedDate = CONVERT(datetime, '9999', 126)
GROUP BY s.NewSeverity
In actual there are only two 'Low' items, hence the output I am getting is I-Low, 2 whereas I want even I-High to appear with 0 count.
The way I would go about this is to create your own table of values using a table value constructor:
SELECT OldSeverity, NewSeverity
FROM (VALUES
('Critical', 'Critical'),
('High', 'Critical'),
('Medium', 'Medium'),
('Low', 'Medium')
) s (OldSeverity, NewSeverity);
This gives a table you can select from, then left join to your existing table:
SELECT Severity = s.NewSeverity,
Total = COUNT(t.Severity)
FROM (VALUES
('Critical', 'Critical'),
('High', 'Critical'),
('Medium', 'Medium'),
('Low', 'Medium')
) s (OldSeverity, NewSeverity)
LEFT JOIN #Test t
ON t.Severity = s.OldSeverity
GROUP BY s.NewSeverity;
This will give the desired results.
Example on SQL Fiddle
EDIT
The problem you have with the way that you are implimenting the query, is that although you have immediately left joined to DimWorkItem you then inner join to subsequent tables and refer to columns in WorkItem in the where clause, which undoes your left join and turns it back into an inner join. You need to place your whole logic into a subquery, and left join to this:
SELECT s.NewSeverity AS 'Severity'
,COUNT(WI.microsoft_vsts_common_severity) AS 'Total'
FROM ( VALUES
('Critical','I-High')
,('High','I-High')
,('Medium','I-Low')
,('Low','I-Low')
)s(OldSeverity,NewSeverity)
LEFT JOIN
( SELECT wi.Severity
FROM DimWorkItem WI (NOLOCK)
JOIN dbo.DimPerson P
ON p.personsk = WI.system_assignedto__personsk
JOIN DimTeamProject TP
ON WI.TeamProjectSK = TP.ProjectNodeSK
JOIN DimIteration Itr (NOLOCK)
ON Itr.IterationSK = WI.IterationSK
JOIN DimArea Ar (NOLOCK)
ON Ar.AreaSK = WI.AreaSK
WHERE TP.ProjectNodeName = 'ABC'
AND WI.System_WorkItemType = 'Bug'
AND WI.Microsoft_VSTS_CMMI_RootCause <> 'Change Request'
AND Itr.IterationPath LIKE '%\ABC\R1234\Test\IT%'
AND WI.System_State NOT IN ( 'Rejected', 'Closed' )
AND WI.System_RevisedDate = CONVERT(datetime, '9999', 126)
) WI
ON WI.Severity = s.OldSeverity
GROUP BY s.NewSeverity;