SQL query multiplying SUM results when joining to multiple transaction tables - sql

I'm developing a report which measures cash performance based on allocation and cancellation dates. To measure this I've queried a transactions sub query which pulls back all transactions and is joined on an account number and transaction from and to dates. This is then summed up at the top of the query.
All works fine when using one sub query however I'm now having to add an extra transactions sub query; 1 to calculate actual payments from the allocation date (to cancellation date or today if value is null) and the 2nd to calculate any cancelled payments from the allocation date + 14 days (to cancellation date or today if value is null).
The first sub query works perfectly but now I've added the second it's multiplying the summed value by 8. I've had this in the past when trying to query this table twice. (Not always by 8). Any ideas?
Thanks
The sums totalling these (TEST1 works fine, TEST2 not so much) and the sub queries:
SUM(CASE WHEN v1.[Transaction Date1] >= dateadd(DD, 1, EOMONTH(getdate(), -1))
THEN v1.[Payments] ELSE 0
END) AS TEST1,
SUM(CASE WHEN v2.[Transaction Date2] >= dateadd(DD, 1, EOMONTH(getdate(), -1))
THEN v2.[Payments2] ELSE 0
END) AS TEST2,
My code:
LEFT JOIN
(SELECT
[Account Number1], [Transaction Date1], SUM([Payments1]) AS [Payments]
FROM
(SELECT
ACCOUNTNO AS [Account Number1],
TRANDT AS [Transaction Date1],
CASE
WHEN TRANSACTIONTYPE = 'Credit'
THEN TRANAMT * -1
ELSE TRANAMT
END [Payments1]
FROM
TRANSACTIONS t WITH (NOLOCK)
JOIN
TRANSACTIONDETAILS td WITH (NOLOCK) ON td.TRANSACTIONID = t.TRANSACTIONS1
JOIN
TRANSACTIONS a WITH (NOLOCK) ON a.ID = TRANSACTIONS1
AND [TRANTYPE] LIKE '%PAY%'
AND [TRANAMT] <> 0
INNER JOIN
ACCOUNTS na WITH (NOLOCK) ON a.ACCOUNTID = ACCOUNTS1
WHERE
TRANSACTIONTYPE = 'Credit') v
GROUP BY
[Account Number1], [Transaction Date1]) v1 ON MAINT.[ACCNO] = v1.[Account Number1]
AND MAINT.[Allocation Date] <= v1.[Transaction Date1]
AND v1.[Transaction Date1] <= MAINT.[Transaction to date]
LEFT JOIN
(SELECT
[Account Number2], [Transaction Date2], SUM([Payments2]) AS [Payments2]
FROM
(SELECT
ACCOUNTNO AS [Account Number2],
TRANDT AS [Transaction Date2],
CASE
WHEN TRANSACTIONTYPE = 'Credit'
THEN TRANAMT * -1
ELSE TRANAMT
END [Payments2]
FROM
TRANSACTIONS t WITH (NOLOCK)
INNER JOIN
TRANSACTIONDETAILS td WITH (NOLOCK) ON td.TRANSACTIONID = t.TRANSACTIONS1
INNER JOIN
TRANSACTIONS a WITH (NOLOCK) ON a.ID = TRANSACTIONS1
AND [TRANTYPE] LIKE '%PAY%'
AND [TRANAMT] <> 0
INNER JOIN
ACCOUNTS na WITH (NOLOCK) ON a.ACCOUNTID = ACCOUNTS1
WHERE
TRANSACTIONTYPE = 'Debit') v
GROUP BY
[Account Number2], [Transaction Date2]) v2 ON MAINT.[ACCNO] = v2.[Account Number2]
AND DATEADD(DD,10,MAINT.[DCA Allocation Date]) <= v2.[Transaction Date2]
AND v2.[Transaction Date2] <= MAINT.[Transaction to date]

Since the inner most subselect is the same in both joins, you should put it in a WITH statement at the top and then just use that twice.
Like this:
WITH v_CTE
AS
(SELECT
ACCOUNTNO AS [Account Number2],
TRANDT AS [Transaction Date2],
CASE
WHEN TRANSACTIONTYPE = 'Credit'
THEN TRANAMT * -1
ELSE TRANAMT
END [Payments2]
FROM
TRANSACTIONS t WITH (NOLOCK)
INNER JOIN
TRANSACTIONDETAILS td WITH (NOLOCK) ON td.TRANSACTIONID = t.TRANSACTIONS1
INNER JOIN
TRANSACTIONS a WITH (NOLOCK) ON a.ID = TRANSACTIONS1
AND [TRANTYPE] LIKE '%PAY%'
AND [TRANAMT] <> 0
INNER JOIN
ACCOUNTS na WITH (NOLOCK) ON a.ACCOUNTID = ACCOUNTS1
WHERE
TRANSACTIONTYPE = 'Debit')
...
LEFT JOIN
(SELECT
[Account Number1], [Transaction Date1], SUM([Payments1]) AS [Payments]
FROM
v_CTE v
GROUP BY
[Account Number1], [Transaction Date1]) v1 ON MAINT.[ACCNO] = v1.[Account Number1]
AND MAINT.[Allocation Date] <= v1.[Transaction Date1]
AND v1.[Transaction Date1] <= MAINT.[Transaction to date]
LEFT JOIN
(SELECT
[Account Number2], [Transaction Date2], SUM([Payments2]) AS [Payments2]
FROM
v_CTE v
GROUP BY
[Account Number2], [Transaction Date2]) v2 ON MAINT.[ACCNO] = v2.[Account Number2]
AND DATEADD(DD,10,MAINT.[DCA Allocation Date]) <= v2.[Transaction Date2]
AND v2.[Transaction Date2] <= MAINT.[Transaction to date]

Related

Sum of SQL instead of a list result

Instead of have a list of rows with daily budget, I just wan't the total SUM of DalyBudget.
How do I do that?
SELECT
(b.MonthBudget /
SUM(wd.WorkingDay) OVER (PARTITION BY YEAR(wd.date), MONTH(wd.date))
)
as DalyBudget
FROM [Navision4].[dbo].[Salesboard Working Days] wd OUTER APPLY
(SELECT COALESCE(ABS(SUM(Amount)), 0) as MonthBudget
FROM [Navision4].[dbo].[Selek Danmark$G_L Budget Entry] b
WHERE MONTH(wd.Date) = MONTH(b.Date) AND
YEAR(wd.date) = YEAR(b.Date) AND
b.[Budget Name] = '2020C' AND
b.[G_L Account No_] LIKE '3%'
) b
WHERE wd.WorkingDay = 1 AND
wd.SalesPersonCode IS NULL AND
wd.companycode = 'Selek Danmark' AND
wd.[Date] >= '2020-07-27' AND wd.[Date] <= '2020-08-17'
Current result:
I'm not so good til advanced SQL, and this dosen't work
SUM(
(b.MonthBudget /
SUM(wd.WorkingDay) OVER (PARTITION BY YEAR(wd.date), MONTH(wd.date))
)
)
as DalyBudget
This is because of your OUTER APPLY results, simply add DISTINCT keyword before you select it.
SELECT DISTINCT
(b.MonthBudget / SUM(wd.WorkingDay) OVER (PARTITION BY YEAR(wd.date), MONTH(wd.date))) AS DalyBudget
FROM [Navision4].[dbo].[Salesboard Working Days] wd OUTER APPLY
(
SELECT COALESCE(ABS(SUM(Amount)), 0) as MonthBudget
FROM [Navision4].[dbo].[Selek Danmark$G_L Budget Entry] b
WHERE MONTH(wd.Date) = MONTH(b.Date) AND YEAR(wd.date) = YEAR(b.Date) AND
b.[Budget Name] = '2020C' AND b.[G_L Account No_] LIKE '3%'
)b
WHERE wd.WorkingDay = 1 AND wd.SalesPersonCode IS NULL AND wd.companycode = 'Selek Danmark' AND
wd.[Date] >= '2020-07-27' AND wd.[Date] <= '2020-08-17'

How do I list the count of occurrences using the over() function, but only display the occurrences that are listed in the result 3 or more times?

How do I list the amount of times each account number has occurred if I only want to see the ones that have occurred 3 times or more?
I'm using a window OVER() function to get the number of times the account number is listed.
SELECT a.ACCOUNTNUMBER AS [Account Number]
, CONCAT(n.FIRST, ' ', n.MIDDLE, ' ', n.LAST) AS [Member Name]
, l.id AS [Loan ID]
, COUNT(a.ACCOUNTNUMBER)
OVER(partition by a.ACCOUNTNUMBER) as [Number of
Tracking Record]
, n.EMAIL AS [Email]
, n.HOMEPHONE AS [Phone Number]
FROM dbo.account a
INNER JOIN dbo.LOAN l
ON a.ACCOUNTNUMBER = l.PARENTACCOUNT
INNER JOIN dbo.LOANTRACKING lt
ON l.PARENTACCOUNT = lt.PARENTACCOUNT
AND l.ID = lt.ID
INNER JOIN dbo.NAME n
ON a.ACCOUNTNUMBER = n.PARENTACCOUNT
WHERE lt.type = 46
AND l.ProcessDate = CONVERT(VARCHAR(8), dateadd(day,-1, getdate()),
112)
AND lt.ProcessDate = CONVERT(VARCHAR(8), dateadd(day,-1, getdate()),
112)
AND a.CLOSEDATE IS NULL
AND lt.EXPIREDATE IS NULL
GROUP BY a.ACCOUNTNUMBER, n.FIRST, n.MIDDLE, n.LAST, l.id, n.email,
n.HOMEPHONE
ORDER BY [Account Number]
Right now my result is giving me the number of times all of the accounts are listed in the "Number of Tracking Record" column. I want to see only the account numbers that have "3" occurrences or above.
My current result:
My Desired Result:
SELECT * -- edit to include only your relevant columnns
FROM
(
SELECT a.ACCOUNTNUMBER AS [Account Number]
, CONCAT(n.FIRST, ' ', n.MIDDLE, ' ', n.LAST) AS [Member Name]
, l.id AS [Loan ID]
, COUNT(a.ACCOUNTNUMBER)
OVER(partition by a.ACCOUNTNUMBER) as [Number of
Tracking Record]
, n.EMAIL AS [Email]
, n.HOMEPHONE AS [Phone Number]
FROM dbo.account a
INNER JOIN dbo.LOAN l
ON a.ACCOUNTNUMBER = l.PARENTACCOUNT
INNER JOIN dbo.LOANTRACKING lt
ON l.PARENTACCOUNT = lt.PARENTACCOUNT
AND l.ID = lt.ID
INNER JOIN dbo.NAME n
ON a.ACCOUNTNUMBER = n.PARENTACCOUNT
WHERE lt.type = 46
AND l.ProcessDate = CONVERT(VARCHAR(8), dateadd(day,-1, getdate()),
112)
AND lt.ProcessDate = CONVERT(VARCHAR(8), dateadd(day,-1, getdate()),
112)
AND a.CLOSEDATE IS NULL
AND lt.EXPIREDATE IS NULL
GROUP BY a.ACCOUNTNUMBER, n.FIRST, n.MIDDLE, n.LAST, l.id, n.email,
n.HOMEPHONE
) MyQuery
WHERE MyQuery.[Number of Tracking Record] >= 3
ORDER BY [Account Number]
I added an "outer" query around yours, using yours as a subquery, and filtered it for those with just the >=3 condition. And I moved the ORDER BY from your inside query to the outer query, as it's just used for ordering the results and not used in the computation itself.

How can I optimised this query since it is causing locks

Its causing locks and I need help optimising it...
Select o.Vehicle as [No Unit], o.Customer, o.CustomerDisplayName as Name, o.Product as Material, P.ProductName as Product,
o.Depot as Works, a.Distance, o.CustTravelTime as [Assumed TravelTime], o.RequiredDateTime as [Required DateTime],o.TimeWindowOrder
as [To Window Provided],ToWindowDateTime as [Window DateTime],o.OrderRef as [Ref No], o.OrderEntryDateTime as [Orderred DateTime],
o.EnteredBy, o.Instructions, o.Warnings, o.Planning, o.AllocationState as Status,o.LoadDocket as Docket, o.LoadingDateTime
as [Commenced Loading], o.IntransitDateTime as [Completed Loading], o.ArrivedDateTime as [Arrived Customer], o.ArrivedDateTime
as [Commenced Unloading], o.UnloadedDateTime as [Completed Unloading], '?' as [DMS], o.CustomerOrder as CustPO,
o.Renegotiated, o.TurnAround, o.StockOut, o.LateDelivery,o.LateOrder,o.StandingOrder,o.NightShift,o.modifier
as [Actual Modifier], t2.Net, t2.Trantype,o.PlannedDateTime, o.VehAssignedDateTime as [Published Date],
t2.DriverName, o.CancelledDateTime from Orders o left outer join Product P on p.Product = o.Product
left outer join AuthPlantCust A on a.Customer = o.Customer and a.Plant = o.Plant --left
join trans T on O.orderref = t.orderref
outer apply ( SELECT Top 1 Docket, Trantype, DriverName, Net FROM Trans t where o.Orderref = t.Orderref AND TranType <> 'SRT'
ORDER BY DespatchdateTime Desc ) T2 where o.RequiredDateTime >= (#DespatchFrom)
and o.RequiredDateTime < (#DespatchTo) and o.Company = 'C' order by o.RequiredDateTime, o.OrderRef
Or advise best practices.

SQL select statement that checks two columns and returns the value from a third [duplicate]

This question already has answers here:
SQL Server Error:"SQL Server Subquery returned more than 1 value"
(2 answers)
Closed 7 years ago.
I am writing a query that accesses multiple tables in the same database. For one of the columns in the select statement, I need to return
Table1.Column4
where Table1.Column = Table3.Column1 AND
Table1.Column2 = Table4.Column1
I have it written as:
SELECT AccNum.FieldValue
FROM PersonFieldValuesVW
INNER JOIN PersonFieldValuesVW AccNum
ON AccNum.PersonId = InPerson.PersonId
INNER JOIN InPerson
ON InPerson.IncidentId = Incident.Id
WHERE AccNum.FieldDescr like '%Account Number%') as [Account Number],
This is returning the error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Here is the full query, any assistance would be appreciated.
SELECT DISTINCT
CaseNum as [Case Number],
ALCategoryVW.Category as [Category],
ALCategoryVW.SubCategory as [Sub Category],
InAssign.AssignToName as [Assigned To],
ReportedDate as [Open Date],
EndDate as [Closed Date], --This a placeholder for a closed date
[Status],
SiteLoc1.Descr as [Loss Location],
LocDetails as [Loss Cost Center],
SiteLoc1.Region as [Region],
SiteLoc1.SubRegion as [Sub Region],
-- SiteLoc2.Descr as [Location Description], **Need this though returning all for the location?
CASE WHEN SAR.FieldId = '604NU' and SAR.FieldValue <> 'False' THEN 'YES' ELSE 'NO' END as [SAR Required],
Summary as [Incident Summary],
Disposition as [Case Disposition],
(
SELECT AccNum.FieldValue
FROM PersonFieldValuesVW
INNER JOIN PersonFieldValuesVW AccNum ON AccNum.PersonId = InPerson.PersonId
INNER JOIN InPerson ON InPerson.IncidentId = Incident.Id
WHERE AccNum.FieldDescr like '%Account Number%'
) as [Account Number],
FORMAT(AuditItemDetail.ItemValue, '#,###') as [Potential Loss],
FORMAT(AuditItemDetail.ItemValue - AuditItemDetail.PreventedExposureAmount, '#,###') as [Actual Loss]
FROM Incident
INNER JOIN ALCategoryVW ON ALCategoryVW.IncidentId = Incident.Id
INNER JOIN InAssign ON InAssign.IncidentId = Incident.Id
INNER JOIN SiteLoc1 ON SiteLoc1.Id = Incident.LocId
INNER JOIN SiteLoc2 ON SiteLoc2.SiteLoc1Id = SiteLoc1.Id
INNER JOIN IncidentFieldValuesVW SAR ON SAR.IncidentId = Incident.Id
INNER JOIN InItem ON InItem.IncidentId = Incident.Id
INNER JOIN AuditItemDetail ON AuditItemDetail.ItemId = InItem.ItemId
INNER JOIN InPerson ON InPerson.IncidentId = Incident.Id
INNER JOIN PersonFieldValuesVW AccNum ON AccNum.PersonId = InPerson.PersonId
This should resolve your error, but I'm not sure it is logically correct. If you have two records being returned in the sub-select, which one is the "right" one.
SELECT DISTINCT
CaseNum as [Case Number],
ALCategoryVW.Category as [Category],
ALCategoryVW.SubCategory as [Sub Category],
InAssign.AssignToName as [Assigned To],
ReportedDate as [Open Date],
EndDate as [Closed Date], --This a placeholder for a closed date
[Status],
SiteLoc1.Descr as [Loss Location],
LocDetails as [Loss Cost Center],
SiteLoc1.Region as [Region],
SiteLoc1.SubRegion as [Sub Region],
-- SiteLoc2.Descr as [Location Description], **Need this though returning all for the location?
CASE WHEN SAR.FieldId = '604NU' and SAR.FieldValue <> 'False' THEN 'YES' ELSE 'NO' END as [SAR Required],
Summary as [Incident Summary],
Disposition as [Case Disposition],
AccNum.FieldValue,
FORMAT(AuditItemDetail.ItemValue, '#,###') as [Potential Loss],
FORMAT(AuditItemDetail.ItemValue - AuditItemDetail.PreventedExposureAmount, '#,###') as [Actual Loss]
FROM Incident
INNER JOIN ALCategoryVW ON ALCategoryVW.IncidentId = Incident.Id
INNER JOIN InAssign ON InAssign.IncidentId = Incident.Id
INNER JOIN SiteLoc1 ON SiteLoc1.Id = Incident.LocId
INNER JOIN SiteLoc2 ON SiteLoc2.SiteLoc1Id = SiteLoc1.Id
INNER JOIN IncidentFieldValuesVW SAR ON SAR.IncidentId = Incident.Id
INNER JOIN InItem ON InItem.IncidentId = Incident.Id
INNER JOIN AuditItemDetail ON AuditItemDetail.ItemId = InItem.ItemId
INNER JOIN InPerson ON InPerson.IncidentId = Incident.Id
LEFT JOIN PersonFieldValuesVW AccNum ON AccNum.PersonId = InPerson.PersonId AND AccNum.FieldDescr like '%Account Number%'
***Updated based on comment.

Calculate difference between two columns sql

in my SQL Query i am Calculating column values by using CASE WHEN THEN ELSE END Condition.
Now i want to find difference between computed column and normal column
My Query
SELECT T.Ticket [Ticket],
TT.TicketType [Ticket Type],
T.Dependency [Dependency],
CASE
WHEN (
SELECT TOP 1 f1.UpdatedOn
FROM TicketTypeFollowUp AS f1
WHERE f1.UpdatedOn < T.UpdatedOn
AND f1.Ticket = 61423
ORDER BY f1.UpdatedOn DESC
) IS NULL
THEN Ticket.TicketRaisedOn
ELSE (
SELECT TOP 1 f1.UpdatedOn
FROM TicketTypeFollowUp AS f1
WHERE f1.UpdatedOn < T.UpdatedOn
AND f1.Ticket = 61423
ORDER BY f1.UpdatedOn DESC
)
END [Start Date],
T.UpdatedOn [End Date],
L.EmpName [Updated By]
FROM dbo.TicketTypeFollowUp T
LEFT JOIN dbo.Ticket
ON T.Ticket = Ticket.Code
LEFT JOIN dbo.TicketType TT
ON T.TicketType = TT.Code
LEFT JOIN LoginUser L
ON T.UpdatedBy = L.Code
WHERE Ticket = 61423
Query Result
Ticket Type Dependency Start Date End Date Updated By
61423 FLM AGS 2013-01-22 15:50:08.757 2013-01-22 18:35:50.893 Kedar S
I want one more column which displays End Time - Start Time I have used CASE hence i am unable to compute difference.
Database is SQL SERVER 2008
with lastUpdate(ticket, lastUpdate) as (
select ticket,
max(updateOn)
from TicketTypeFollowUp
group by ticket)
SELECT T.Ticket [Ticket],
TT.TicketType [Ticket Type],
T.Dependency [Dependency],
coalesce(lastUpdate, ticketRaisedOn) [Start Date],
T.UpdatedOn [End Date],
datediff(mi, coalesce(lastUpdate, ticketRaisedOn), T.UpdatedOn) durationMins,
L.EmpName [Updated By]
FROM dbo.TicketTypeFollowUp T
LEFT JOIN dbo.Ticket
ON T.Ticket = Ticket.Code
LEFT JOIN dbo.TicketType TT
ON T.TicketType = TT.Code
LEFT JOIN LoginUser L
ON T.UpdatedBy = L.Code
left join lastUpdate lu on t.ticket = lu.ticket
WHERE Ticket = 61423
You can use your current query as a CTE or a derived table. Here is an example using a CTE:
;WITH CTE AS
(
-- your current query here
)
SELECT *, DATEDIFF(MINUTE,[Start Date],[End Date]) [End Time - Start Time]
FROM CTE