SQL Server 2008 Running Total - sql

I'm aware this has been asked but I'm completely baffled.
Trying to run a running total by day using SQL Server 2008. Have looked at solutions elsewhere but would am still completely perplexed.
The below code shows Daily sales but I cannot make a running total fit. Have looked at the similar solutions here but no luck. Have looked at partition by, order by, CTE etc but I'm just not there yet with SQL.
Would appreciate help, my code is below. I know this only returns the total grouped by day...
SELECT
dim_invoice_date.invoice_date AS 'Invoice Date',
round(SUM(invoice_amount_corp),2) AS 'Sales'
FROM
fact_om_bud_invoice
JOIN
dim_invoice_date ON fact_om_bud_invoice.dim_invoice_date_key = dim_invoice_date.dim_invoice_date_key
WHERE
dim_invoice_date.current_cal_month IN ('Current')
AND fact_om_bud_invoice.budget_code IN ('BUDGET')
GROUP BY
dim_invoice_date.invoice_date
HAVING
ROUND(SUM(invoice_amount_corp), 2) <> 0
ORDER BY
'Invoice Date'
This returns the output:
Invoice Date Sales
-----------------------
4/10/2016 24,132
5/10/2016 15,849
6/10/2016 24,481
7/10/2016 10,243
10/10/2016 42,398
11/10/2016 24,187
Required format is something like:
Invoice Date Sales Running Sales
-------------------------------------------
04/10/2016 24,132 24,132
05/10/2016 15,849 39,981
06/10/2016 24,481 64,462
07/10/2016 10,243 74,705
10/10/2016 42,398 117,103
11/10/2016 24,187 141,290
dim_invoice_date is a numeric field, it's looking up a separate date table to display as date time.

For example, can use WITH common_table_expression
WITH cte AS
(
SELECT
ROW_NUMBER() OVER(ORDER BY h.[Date]) RowN,
h.[Date],
SUM(s.Quantity) q
FROM
Sales s
JOIN Headers h
ON s.ID_Headers = h.ID
WHERE
h.[Date] > '2016.10.31'
GROUP BY
h.[Date]
)
SELECT
c.[Date],
c.q,
SUM(c1.q)
FROM
cte c
JOIN cte c1
ON c1.RowN <= c.RowN
GROUP BY
C.[Date],
c.q
ORDER BY
c.[Date]

Related

CASE condition and SUM() common table expressions or Group By

Hope some can help ? I have a 3rd party software were i can do custom sql querys but not able to change any of the database. Struggling to get the result i would like.
Do I use GROUP BY or CTE to get the result i need?
WITH CTE AS (
SELECT tblTicketsSummary.fldDateScheduled AS [Scheduled],
tblTicketsRow.fldStartTime AS [TIME], tblTicketsRow.fldPs AS
[s],tblTicketsRow.fldPrice AS PR,
tblTicketsSummary.fldFirstName+' '+tblTicketsSummary.fldLastName
AS [Client], ROW_NUMBER() OVER
(PARTITION BY tblTicketsSummary.fldTicketID ORDER BY
tblTicketsRow.fldTicketID) AS C, tblTicketsSummary.fldDateClosed
AS [Date Closed],
CASE WHEN tblTicketsRow.fldPs ='p' THEN tblTicketsRow.fldPrice
ELSE £0.00 END AS Product,
CASE WHEN tblTicketsRow.fldPs ='s' THEN tblTicketsRow.fldPrice
ELSE £0.00 END AS Services,
FROM tblTicketsSummary INNER JOIN
tblTicketsRow ON tblTicketsSummary.fldTicketID = tblTicketsRow.fldTicketID
WHERE (fldDateVoided IS NULL) AND (NOT(fldDateClosed IS NULL))
GetUserDate('AND','fldDateClosed','') AND tblTicketsRow.fldEmployeeName ='Tina Young'
AND tblTicketsSummary.fldTotal >1 )
SELECT * FROM CTE ORDER BY Scheduled ASC, TIME ASC
This give me the result below . I have removed Where c=1 in the last select which i will put back in the final query which give me the first result by time which is what i want. The bit i am struggling with is. I would like to add the prices of all products together and the prices of all service together to give a total of products and services sold. Then a grand total of services and product together in the final query .
Scheduled TIME s PR Client C Date Closed Product Services Total
17/07/2020 17:00 S £10.00 Ben Preston 1 17/07/2020 £0.00 £10.00 s+p
17/07/2020 17:45 S £1.00 Ben Preston 2 17/07/2020 £0.00 £1.00 s+p
17/07/2020 P £19.00 Ben Preston 3 17/07/2020 £19.00 £0.00 s+p
17/07/2020 P £10.00 Ben Preston 4 17/07/2020 £10.00 £0.00 s+p
The Result i would like is below. The final part of the query is as below. I am only able to custom query's in the 3rd party software.
SELECT * FROM CTE WHERE c=1 ORDER BY Scheduled ASC, TIME ASC
Scheduled TIME Client C Date Closed Product Services Total
17/07/2020 17:00 Ben Preston 1 17/07/2020 £29.00 £11.00 £40.00
I hope I have formatted this right for people to understand. Thank you for any help you can provide.
Seems like you simply need to add two Group Sums to your existing CTE and then add them in your final Select:
WITH CTE AS (
SELECT tblTicketsSummary.fldDateScheduled AS [Scheduled],
tblTicketsRow.fldStartTime AS [TIME],
tblTicketsRow.fldPs AS [s],tblTicketsRow.fldPrice AS PR,
tblTicketsSummary.fldFirstName+' '+tblTicketsSummary.fldLastName AS [Client],
ROW_NUMBER()
OVER (PARTITION BY tblTicketsSummary.fldTicketID
ORDER BY tblTicketsRow.fldStartTime) AS C,
tblTicketsSummary.fldDateClosed AS [Date Closed],
SUM(CASE WHEN tblTicketsRow.fldPs ='p' THEN tblTicketsRow.fldPrice ELSE £0.00 END)
OVER (PARTITION BY tblTicketsSummary.fldTicketID) AS Product,
SUM(CASE WHEN tblTicketsRow.fldPs ='s' THEN tblTicketsRow.fldPrice ELSE £0.00 END)
OVER (PARTITION BY tblTicketsSummary.fldTicketID) AS Services
FROM tblTicketsSummary
INNER JOIN tblTicketsRow
ON tblTicketsSummary.fldTicketID = tblTicketsRow.fldTicketID
WHERE (fldDateVoided IS NULL) AND (NOT(fldDateClosed IS NULL))
--GetUserDate('AND','fldDateClosed','') AND tblTicketsRow.fldEmployeeName ='Tina Young'
AND tblTicketsSummary.fldTotal >1 )
SELECT cte.*,
Product + Services as total
FROM CTE
WHERE C = 1
ORDER BY Scheduled ASC, TIME ASC;
Btw, the ORDER BY tblTicketsRow.fldTicketID on your ROW_NUMBER is not based on a unique column, thus the order of rows is not guaranteed. You probably want order by tblTicketsRow.fldStartTime instead.

sql running total

Im trying to generate a running total by month and year. Ive tried a few examples but I cant get it working. This is the sql I have and I would want to create a running total for the totalclients column
Month| Year| TotalClients| Running Total
Jan |2014| 1| 1
Feb| 2014| 4| 5
Mar| 2014| 8| 13
select Month, Year, TotalClients
From Total
This was the code I was trying to use, ive used a declare table as the main data comes from a different query but this should be the bit you need. I also commented out one of the from lines as I was trying out both way, the commented out line was in a few examples on the net but I couldn't get it working
select t1.monthstart, t1.yearstart, t1.TotalClients, sum(t2.TotalClients) as 'RunningTotal'
from #Totals t1 inner join #Totals t2 on t1.monthstart = t2.monthstart and t1.yearstart = t2.yearstart
--from #Totals t1, #Totals t2
WHERE t1.MonthStart <= t2.MonthStart and t1.Yearstart <= t2.Yearstart
GROUP BY t1.Yearstart, t1.MonthStart, t1.TotalClients
ORDER BY t1.yearstart , t1.monthstart
As #xQbert posted in comments above (I advise reading that article), SQL Server "Windowing Functions" is what you want to use in version 2012+. Windowing functions are flexible and powerful, and far more efficient than self-joins.
As an actual answer, here would be some possible code for you to use:
SELECT YearStart, MonthStart,
ClientCount = SUM(TotalClients) OVER (
PARTITION BY YearStart, MonthStart
ORDER BY YearStart, MonthStart RANGE UNBOUNDED PRECEDING
)
FROM Totals t1
ORDER BY YearStart, MonthStart
I used this in the end, I added a faulldate in to simplify what I wanted and it worked, I think the issue was in the join I used it had the <= the wrong way around.
SELECT
st1.invoicestartdate,
st1.TotalClients,
RunningTotal = SUM(st2.TotalClients)
FROM
#Totals AS st1
INNER JOIN
#Totals AS st2
ON st2.invoicestartdate <= st1.invoicestartdate
GROUP BY st1.invoicestartdate, st1.TotalClients
ORDER BY st1.invoicestartdate;
This query works for SQL Server 2012 and up. I assumed Month is numeric (Jan = 1, Feb = 2, etc.)
SELECT *,
SUM(t.TotalClients) OVER (PARTITION BY t.[Year] ORDER BY t.[Month])
FROM #Totals t
It will reset the client count once the year changes. To keep it going, change the SUM clause to
SUM(t.TotalClients) OVER (ORDER BY t.[Year], t.[Month])

How to check newer than or equal to a date on access SQL

Currently I have two tables, using Access 2007
TimeSheet(empID, TimeSheet, hours)
and
Rates(empID,Rate,PromotionDate)
How do I select the correct billing rates of employee based on their date of promotion?
For example, I have
Rates(001,10,#01/01/2013#)
Rates(001,15,#01/05/2013#)
Rates(002,10,#01/01/2013#)
and
Timesheet(001,#02/01/2013#,5)
Timesheet(001,#02/05/2013#,5)
Timesheet(002,#02/01/2013#,7)
In this case, I want to show that if empID 001 submited a time sheet at 02/01/2013 it would be billed with $10/hr
, but his timesheets starting at May 1st would be billed with $15/hr
My query right now is
SELECT t.empID , t.timesheet, r.hours ,
(SELECT rate FROM rate WHERE t.timeSheet >= r.promotionDate) AS RateBilled
FROM rate AS r , timesheet AS t
WHERE r.empid = t.empid
When ran, it shows a message of “At most one record can be returned by this subquery”
Any help would be appreciated, thanks.
Edit:
I have some strange output using the sql
SELECT t.empID, t.timesheet, r.rate AS RateBilled
FROM Rates AS r, timesheet AS t
WHERE r.empid=t.empid And t.timeSheet>=r.promotionDate
GROUP BY t.empID, t.timesheet, r.rate, r.promotionDate
HAVING r.promotionDate=MAX(r.promotionDate);
as you can see the output table ratebilled for empID 1 is switching back and forth from 10 to 15, even though past May 01, it should all be using 15 ,
any help is appreciated, thanks.
The select subquery you have setup potentially returns multiple values where only one should be returned. Consider the case where there may be two promotions and a recent timesheet, then the select will return two values because on both occasions the timesheet is newer than the promotion.
Try using the following as your subquery:
SELECT TOP 1 rate FROM rate
WHERE t.timeSheet >= r.promotionDate
ORDER BY r.promotionDate DESC
N.B. I don't think the above is terribly efficient. Instead try something like
SELECT t.empID , t.timesheet, r.hours , r.rate AS RateBilled
FROM rate AS r , timesheet AS t
WHERE r.empid = t.empid AND t.timeSheet >= r.promotionDate
GROUP BY t.empID, t.timesheet
HAVING r.promotionDate = MAX( r.promotionDate);

Incorrect sum when I join a second table

This is the first time I ask for your help,
Actually I have to create a query, and did a similar example for it. I have two tables,
Report (ReportID, Date, headCount)
Production(ProdID, ReportID, Quantity)
My question is using this query, I get a wrong result,
SELECT
Report.date,
SUM(Report.HeadCount) AS SumHeadCount,
SUM(Production.Quantity) AS SumQuantity
FROM
Report
INNER JOIN
Production ON Report.ReportID = Production.ReportID
GROUP BY
Date
ORDER BY
Date
I guess some rows are being counted more than once, could you please give me a hand?
EDIT
if i run a query to get a sum of headcount grouped by day, I get:
date Headcount
7/2/2012 1843
7/3/2012 1802
7/4/2012 1858
7/5/2012 1904
also for Production Qty I get:
2012-07-02 8362
2012-07-03 8042
2012-07-04 8272
2012-07-05 9227
but when i combine the both queries i get i false one, i expect on 2 july 8362 qty against 1843, but i get:
day TotalHeadcount totalQty
7/2/2012 6021 8362
7/3/2012 7193 8042
7/4/2012 6988 8272
7/5/2012 7197 9227
This may be helpful
SELECT Report.ReportDate,
Sum(Report.HeadCount) AS SumHeadCount,
ProductionSummary.SumQuantity
FROM Report
INNER JOIN (SELECT ReportID,
Sum(Production.Quantity) AS SumQuantity
FROM Production
GROUP BY ReportID) AS ProductionSummary
ON Report.ReportID = ProductionSummary.ReportID
GROUP BY ReportDate
ORDER BY ReportDate
One way of avoiding this (subject to RDBMS support) would be
WITH R
AS (SELECT *,
Sum(HeadCount) OVER (PARTITION BY date) AS SumHeadCount
FROM Report)
SELECT R.date,
SumHeadCount,
Sum(P.Quantity) AS SumQuantity
FROM R
JOIN Production P
ON R.ReportID = P.ReportID
GROUP BY R.date, SumHeadCount
ORDER BY R.date
Group records per date using following
SELECT ReportSummary.ReportDate, SUM(ReportSummary.SumHeadCount) AS SumHeadCount, SUM(ProductionSummary.SumQuantity) AS SumQuantity
FROM
(
SELECT Report.ReportDate, SUM(Report.HeadCount) AS SumHeadCount
FROM Report
GROUP BY Report.ReportDate
) AS ReportSummary
INNER JOIN
(
SELECT Report.ReportDate, Sum(Production.Quantity) AS SumQuantity
FROM Production
INNER JOIN Report
ON Report.ReportID = Production.ReportID
GROUP BY Report.ReportDate
) AS ProductionSummary
ON ReportSummary.ReportDate = ProductionSummary.ReportDate
GROUP BY ReportSummary.ReportDate
ORDER BY ReportSummary.ReportDate
We have same problem but I solved it. Try this.
SELECT tbl_report.SumHeadCount, tbl_report.date, tbl_production.SumQuantity
FROM
( select date,
SUM(HeadCount) AS SumHeadCount FROM Report GROUP by date)as tbl_report
JOIN
( select SUM(Quantity) AS SumQuantity, date FROM Production GROUP by date)as tbl_production
WHERE tbl_report.date = tbl_production.date

SQL query to identify seasonal sales items

I need a SQL query that will identify seasonal sales items.
My table has the following structure -
ProdId WeekEnd Sales
234 23/04/09 543.23
234 30/04/09 12.43
432 23/04/09 0.00
etc
I need a SQL query that will return all ProdId's that have 26 weeks consecutive 0 sales. I am running SQL server 2005. Many thanks!
Update: A colleague has suggested a solution using rank() - I'm looking at it now...
Here's my version:
DECLARE #NumWeeks int
SET #NumWeeks = 26
SELECT s1.ProdID, s1.WeekEnd, COUNT(*) AS ZeroCount
FROM Sales s1
INNER JOIN Sales s2
ON s2.ProdID = s1.ProdID
AND s2.WeekEnd >= s1.WeekEnd
AND s2.WeekEnd <= DATEADD(WEEK, #NumWeeks + 1, s1.WeekEnd)
WHERE s1.Sales > 0
GROUP BY s1.ProdID, s1.WeekEnd
HAVING COUNT(*) >= #NumWeeks
Now, this is making a critical assumption, namely that there are no duplicate entries (only 1 per product per week) and that new data is actually entered every week. With these assumptions taken into account, if we look at the 27 weeks after a non-zero sales week and find that there were 26 total weeks with zero sales, then we can deduce logically that they had to be 26 consecutive weeks.
Note that this will ignore products that had zero sales from the start; there has to be a non-zero week to anchor it. If you want to include products that had no sales since the beginning, then add the following line after `WHERE s1.Sales > 0':
OR s1.WeekEnd = (SELECT MIN(WeekEnd) FROM Sales WHERE ProdID = s1.ProdID)
This will slow the query down a lot but guarantees that the first week of "recorded" sales will always be taken into account.
SELECT DISTINCT
s1.ProdId
FROM (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s1
INNER JOIN (
SELECT
ProdId,
ROW_NUMBER() OVER (PARTITION BY ProdId ORDER BY WeekEnd) AS rownum,
WeekEnd
FROM Sales
WHERE Sales <> 0
) s2
ON s1.ProdId = s2.ProdId
AND s1.rownum + 1 = s2.rownum
AND DateAdd(WEEK, 26, s1.WeekEnd) = s2.WeekEnd;