I have a temp table with deals, dates, and volumes in it. What I need is to calculate the days between the effective dates in a dynamic fashion. Also complicating this, the first for each deal is in the past but the represents the current deal volume. So for that line I need to return the number of days from today to the next effective date for that deal. Furthermore, on the last effective date for each deal, I have to run a subquery to grab the contract end date from another temp table.
Sample of the temp table and the sample return needed:
Sample
Here's an option to explore.
Basically what you're after for each record:
Previous record EffectiveDate based on Deal_ID - LAG()
Next EffectiveDate after today based on Deal_ID - Sub query
Then you can evaluate and figure out days based on those values.
Here's a temp table and some sample data:
CREATE TABLE #Deal
(
[Row_ID] INT
, [Deal_ID] BIGINT
, [EffectiveDate] DATE
, [Volume] BIGINT
);
INSERT INTO #Deal (
[Row_ID]
, [Deal_ID]
, [EffectiveDate]
, [Volume]
)
VALUES ( 1, 1479209, '2018-11-01', 5203 )
, ( 2, 1479209, '2019-03-01', 2727 )
, ( 3, 1479209, '2019-04-01', 1615 )
, ( 4, 1479209, '2019-06-01', 1325 )
, ( 5, 1598451, '2018-12-01', 2000 )
, ( 6, 1598451, '2019-04-01', 4000 )
, ( 7, 1598451, '2019-08-01', 4000 );
Here's an example query using LAG() and sub-query:
SELECT *
-- LAG here partitioned by the Deal_ID, will return NULL if first record.
, LAG([dl].[EffectiveDate], 1, NULL) OVER ( PARTITION BY [dl].[Deal_ID]
ORDER BY [dl].[EffectiveDate]
) AS [PreviousRowEffectiveData]
--Sub query to get min EffectiveDate that is greater than today
, (
SELECT MIN([dl1].[EffectiveDate])
FROM #Deal [dl1]
WHERE [dl1].[Deal_ID] = [dl].[Deal_ID]
AND [dl1].[EffectiveDate] > GETDATE()
) AS [NextEffectiveDateAfterToday]
FROM #Deal [dl]
Giving you these results:
Row_ID Deal_ID EffectiveDate Volume PreviousRowEffectiveData NextEffectiveDateAfterToday
----------- -------------------- ------------- -------------------- ------------------------ ---------------------------
1 1479209 2018-11-01 5203 NULL 2019-03-01
2 1479209 2019-03-01 2727 2018-11-01 2019-03-01
3 1479209 2019-04-01 1615 2019-03-01 2019-03-01
4 1479209 2019-06-01 1325 2019-04-01 2019-03-01
5 1598451 2018-12-01 2000 NULL 2019-04-01
6 1598451 2019-04-01 4000 2018-12-01 2019-04-01
7 1598451 2019-08-01 4000 2019-04-01 2019-04-01
Now that we have that we can use that in a sub query and then implement the business rules for DAYS if I understood correctly:
First row for a Deal_ID, number of days from next effective date after today to today.
If not first, number of days from previous effective date to row effective date.
Example query:
SELECT *
--Case statement, if previousrow null(first record) difference in days of datday and NextEfectiveDateAfterToday
--Else we will do the difference in days of previousrow and this rows effective date.
, CASE WHEN [Deal].[PreviousRowEffectiveData] IS NULL THEN DATEDIFF(DAY, GETDATE(), [Deal].[NextEffectiveDateAfterToday])
ELSE DATEDIFF(DAY, [Deal].[PreviousRowEffectiveData], [Deal].[EffectiveDate])
END AS [DAYS]
FROM (
SELECT *
-- LAG here partioned by the Deal_ID, we'l return NULL if first record.
, LAG([dl].[EffectiveDate], 1, NULL) OVER ( PARTITION BY [dl].[Deal_ID]
ORDER BY [dl].[EffectiveDate]
) AS [PreviousRowEffectiveData]
--Sub query to get min EffectiveDate that is greater than today
, (
SELECT MIN([dl1].[EffectiveDate])
FROM #Deal [dl1]
WHERE [dl1].[Deal_ID] = [dl].[Deal_ID]
AND [dl1].[EffectiveDate] > GETDATE()
) AS [NextEffectiveDateAfterToday]
FROM #Deal [dl]
) AS [Deal];
Giving us the final results of:
Row_ID Deal_ID EffectiveDate Volume PreviousRowEffectiveData NextEffectiveDateAfterToday DAYS
----------- -------------------- ------------- -------------------- ------------------------ --------------------------- -----------
1 1479209 2018-11-01 5203 NULL 2019-03-01 14
2 1479209 2019-03-01 2727 2018-11-01 2019-03-01 120
3 1479209 2019-04-01 1615 2019-03-01 2019-03-01 31
4 1479209 2019-06-01 1325 2019-04-01 2019-03-01 61
5 1598451 2018-12-01 2000 NULL 2019-04-01 45
6 1598451 2019-04-01 4000 2018-12-01 2019-04-01 121
7 1598451 2019-08-01 4000 2019-04-01 2019-04-01 122
Related
I have a calendar table and I want to show each month in a grid, and when I select a month from the table, I have some row with monthday and weekday columns, but I must convert it to multiple rows per week to show the month in the grid.
my select command to get month info is something like this
SELECT Monthday, Weekday FROM Calendar Where Month = 5
that Results to this :
Monthday | Weekday
--------- --------
1 4
2 5
3 6
4 7
5 1
6 2
7 3
8 4
. .
. .
. .
and I Want to Convert it To Something like this
1 | 2 | 3 | 4 | 5 | 6 | 7
-- --- --- --- --- --- --
1 2 3 4
5 6 7 8 . . .
just like a calendar grid.
I think the answer is by Pivot, but I don't know how, Do you know a solution how to convert my select command?
Let's suppose you have a calendar table with the structure mentioned below, which is populated with a query like the following:
CREATE TABLE Calendar (
TheDate DATE PRIMARY KEY,
YearNumber SMALLINT,
MonthNumber SMALLINT,
DayNumber SMALLINT,
WeekdayNumber SMALLINT
)
INSERT INTO dbo.Calendar (TheDate, YearNumber, MonthNumber, DayNumber, WeekdayNumber)
SELECT x.TheDate,
YEAR(x.TheDate) AS YearNumber, MONTH(x.TheDate) AS MonthNumber, DAY(x.TheDate) AS DayNumber,
(DATEPART(WEEKDAY,x.TheDate)+##DATEFIRST-2)%7+1 AS WeekdayNumber
FROM (
SELECT TOP 365 DATEADD(DAY,N-1,'20210101') AS TheDate
FROM (SELECT ROW_NUMBER() OVER (ORDER BY low) AS N FROM master..spt_values) t
ORDER BY N
) x
The formula for WeekdayNumber is written this way to ignore the SET DATEFIRST setting and always consider Monday as the first day of week. If you prefer another day to be the first in the week, adjust -2 to another value.
To display something like a calendar for a particular month, you can use a query like this:
SELECT * FROM (
SELECT DayNumber, WeekdayNumber,
DENSE_RANK() OVER (ORDER BY DayNumber-WeekdayNumber) AS WeekNumber
FROM dbo.Calendar WHERE YearNumber=2021 AND MonthNumber=5
) t
PIVOT (MAX(DayNumber) FOR WeekdayNumber IN ([1],[2],[3],[4],[5],[6],[7])) p
This produces the following result:
WeekNumber 1 2 3 4 5 6 7
-------------------- ------ ------ ------ ------ ------ ------ ------
1 NULL NULL NULL NULL NULL 1 2
2 3 4 5 6 7 8 9
3 10 11 12 13 14 15 16
4 17 18 19 20 21 22 23
5 24 25 26 27 28 29 30
6 31 NULL NULL NULL NULL NULL NULL
I am using just the DayNumber and WeekdayNumber columns to compute a week number and then I am using PIVOT to arrange the values for DayNumber in the desired format.
Hoping someone has run across this issue previously and has a solution.
I am trying to find customers who lapse based off subscription periods rather than a single order date.
Lapse is defined by us as not making a purchase/renewal within 30 days of the end of their subscription. A customer can have multiple subscriptions simultaneously and subscriptions can vary in length.
I have a data set that includes customerIDs, Orders, the subscription start date, the subscription expire date, and that order’s rank in the customer’s order history, something like this:
CREATE TABLE #Subscriptions
(CustomerID INT,
Orderid INT,
SubscriptionStart DATE,
SubscriptionEnd DATE,
OrderNumber INT);
INSERT INTO #Subscriptions
VALUES(1, 111111, '2017-01-01', '2017-12-31', 1),
(1, 211111, '2018-01-01', '2019-12-31' ,2),
(1, 311121, '2018-10-01', '2018-10-02', 3),
(1, 451515, '2019-02-01', '2019-02-28', 4),
(2, 158797, '2018-07-01', '2018-07-31', 1),
(2, 287584, '2018-09-01', '2018-12-31', 2),
(2, 387452, '2019-01-01', '2019-01-31', 3),
(3, 187498, '2019-01-01', '2019-02-28', 1),
(3, 284990, '2019-02-01', '2019-02-28', 2),
(4, 184849, '2019-02-01', '2019-02-28', 1)
Within this data set, customer 2 would have lapsed on 2018-07-31. Since Customer 1 has a subscription of 2017-01-01 - 2017-12-31 and then one that starts 2018-01-01 and ends 2019-12-31 they cannot lapse within that time period even if other orders made by the customer would qualify.
I have attempt some of simple gap calculations using LEAD() and LAG(), however, I have had no success due to the variable lengths of the subscription period where a single subscription can span across multiple other orders. Eventually, we will use this to calculate monthly churn rate across approximately 5 million records.
You're overthinking this trying to use LEAD() and LAG(). All you need is a NOT EXISTS() function in the WHERE clause
In psuedocode:
SELECT...FROM...
WHERE {SubscriptionEnd is at least 30 days in the past}
AND NOT EXISTS(
{A row for the same Customer where the StartDate is 30 days or less after this EndDate}
)
This one looks to be a tricky one. You are correct about the problem with using the LEAD() and LAG() functions. It stems from customers being able to have multiple subscriptions of variable length. So we need to deal with that issue first. Let's begin with creating a single list of dates instead of having a list of SubscriptionStart and SubscriptionEnd.
SELECT
CustomerId,
OrderId,
1 AS Activity,
SubscriptionStart AS ActivityDate
FROM
#Subscriptions
UNION ALL
SELECT
CustomerId,
OrderId,
-1 AS Activity,
SubscriptionEnd AS ActivityDate
FROM
#Subscriptions
ORDER BY
CustomerId,
ActivityDate
CustomerId OrderId Activity ActivityDate
----------- ----------- ----------- ------------
1 111111 1 2017-01-01
1 111111 -1 2017-12-31
1 211111 1 2018-01-01
1 311121 1 2018-10-01
1 311121 -1 2018-10-02
1 451515 1 2019-02-01
1 451515 -1 2019-02-28
1 211111 -1 2019-12-31
2 158797 1 2018-07-01
2 158797 -1 2018-07-31
2 287584 1 2018-09-01
2 287584 -1 2018-12-31
2 387452 1 2019-01-01
2 387452 -1 2019-01-31
3 187498 1 2019-01-01
3 284990 1 2019-02-01
3 187498 -1 2019-02-28
3 284990 -1 2019-02-28
4 184849 1 2019-02-01
4 184849 -1 2019-02-28
Notice the additional Activity field. It is 1 for the SubscriptionStart and -1 for the SubscriptionEnd.
Using this new Activity field it is possible to find places where there might be a lapse in the customer's subscriptions. At the same time use LEAD() to find the NextDate.
;WITH SubscriptionList AS (
SELECT
CustomerId,
OrderId,
1 AS Activity,
SubscriptionStart AS ActivityDate
FROM
#Subscriptions
UNION ALL
SELECT
CustomerId,
OrderId,
-1 AS Activity,
SubscriptionEnd AS ActivityDate
FROM
#Subscriptions
)
SELECT
CustomerId,
OrderId,
Activity,
SUM(Activity) OVER(PARTITION BY CustomerId ORDER BY ActivityDate ROWS UNBOUNDED PRECEDING) as SubscriptionCount,
ActivityDate,
LEAD(ActivityDate, 1, GETDATE()) OVER(PARTITION BY CustomerId ORDER BY ActivityDate) AS NextDate,
DATEDIFF(d, ActivityDate, LEAD(ActivityDate, 1, GETDATE()) OVER(PARTITION BY CustomerId ORDER BY ActivityDate)) AS LapsedDays
FROM
SubscriptionList
ORDER BY
CustomerId,
ActivityDate
CustomerId OrderId Activity SubscriptionCount ActivityDate NextDate LapsedDays
----------- ----------- ----------- ----------------- ------------ ---------- -----------
1 111111 1 1 2017-01-01 2017-12-31 364
1 111111 -1 0 2017-12-31 2018-01-01 1
1 211111 1 1 2018-01-01 2018-10-01 273
1 311121 1 2 2018-10-01 2018-10-02 1
1 311121 -1 1 2018-10-02 2019-02-01 122
1 451515 1 2 2019-02-01 2019-02-28 27
1 451515 -1 1 2019-02-28 2019-12-31 306
1 211111 -1 0 2019-12-31 2019-02-28 -306
2 158797 1 1 2018-07-01 2018-07-31 30
2 158797 -1 0 2018-07-31 2018-09-01 32
2 287584 1 1 2018-09-01 2018-12-31 121
2 287584 -1 0 2018-12-31 2019-01-01 1
2 387452 1 1 2019-01-01 2019-01-31 30
2 387452 -1 0 2019-01-31 2019-02-28 28
3 187498 1 1 2019-01-01 2019-02-01 31
3 284990 1 2 2019-02-01 2019-02-28 27
3 187498 -1 1 2019-02-28 2019-02-28 0
3 284990 -1 0 2019-02-28 2019-02-28 0
4 184849 1 1 2019-02-01 2019-02-28 27
4 184849 -1 0 2019-02-28 2019-02-28 0
Adding running total on the Activity field will effectively give the number of active subscriptions. While it is greater than 0 a lapse is not possible. So focus in on the rows WHERE the SubscriptionCount is zero.
Using LEAD() get the NextDate. If there isn't a next date then default to today. If the SubscriptionCount is 0 then the NextDate has to be from a new subscription and the NextDate will be the date that the new subscription starts. Using DATEDIFF count the number of days between the SubscriptionEnd and the SubscriptionBegin if it is > 30 days then there was a lapse. Sounds like a good WHERE statement.
;WITH SubscriptionList AS (
SELECT
CustomerId,
OrderId,
1 AS Activity,
SubscriptionStart AS ActivityDate
FROM
#Subscriptions
UNION ALL
SELECT
CustomerId,
OrderId,
-1 AS Activity,
SubscriptionEnd AS ActivityDate
FROM
#Subscriptions
)
, FindLapse AS (
SELECT
CustomerId,
OrderId,
Activity,
SUM(Activity) OVER(PARTITION BY CustomerId ORDER BY ActivityDate ROWS UNBOUNDED PRECEDING) as SubscriptionCount,
ActivityDate,
LEAD(ActivityDate, 1, GETDATE()) OVER(PARTITION BY CustomerId ORDER BY ActivityDate) AS NextDate
FROM
SubscriptionList
)
SELECT
CustomerId,
OrderId,
Activity,
SubscriptionCount,
ActivityDate,
NextDate,
DATEDIFF(d, ActivityDate, NextDate) AS LapsedDays
FROM
FindLapse
WHERE
SubscriptionCount = 0
AND DATEDIFF(d, ActivityDate, NextDate) >= 30
CustomerId OrderId Activity SubscriptionCount ActivityDate NextDate LapsedDays
----------- ----------- ----------- ----------------- ------------ ---------- -----------
2 158797 -1 0 2018-07-31 2018-09-01 32
Looks like we have a winner!
I need to update a foreign key in table 1 with the correct entry based on table 2. The correct foreign key is the earliest date that falls after, but not before the next effective dates in table 2. If there are multiple entries in table 2 with the same effective date, then use the modified date column as a tie breaker and pick the most recent one. Here is the based table structure (all dates are in Date format):
Table 1
pK1 PeriodStartDate pK2
1 2016-04-01 00:00:00.000
2 2016-07-01 00:00:00.000
Table 2
pK2 EffectiveFrom ModifiedDate
3 2016-03-01 00:00:00.000 2016-04-01 00:00:00.000
4 2016-05-01 00:00:00.000 2016-06-01 00:00:00.000
5 2016-05-01 00:00:00.000 2016-06-02 00:00:00.000
So in the above example table 1 would look like this:
pK1 PeriodStartDate pK2
1 2016-04-01 00:00:00.000 3
2 2016-07-01 00:00:00.000 5
This is because for row 1 it falls between March 1st and May 1st (from table 2). And for row 2 it is after the last date, but as there are two similar start dates we choose the last modified.
I'm not sure of the solution. I was trying something like this:
UPDATE table1
SET pK2 = table2.pK2
FROM table2
WHERE PeriodStartDate > (SELECT FIRST(table2.EffectiveFrom) FROM table2)
I'm just not sure how to find an entry that is bounded by another row (and then needs another column for the tie breaker)
First off, you need to apply a row_number() over Table2, partitioned on the PeriodStart and ordered by the ModifiedDate (desc). Call this MaxModified; and 1 is always the most recently modified record.
pK2 PeriodStart ModifiedDate MaxModified
3 2016-03-01 00:00:00.000 2016-04-01 00:00:00.000 1
5 2016-05-01 00:00:00.000 2016-06-02 00:00:00.000 1
4 2016-05-01 00:00:00.000 2016-06-01 00:00:00.000 2
Then, for only where MaxModified=1, you add a new "id" to this so we can line up a start date, with the next rows start date (our end date). This is also done with the row_number() function ordered by the PeriodStart.
pK2 PeriodStart ModifiedDate MaxModified myID
3 2016-03-01 00:00:00.000 2016-04-01 00:00:00.000 1 1
5 2016-05-01 00:00:00.000 2016-06-02 00:00:00.000 1 2
Then we take that result and join it to itself offset by one row to get an end date value for each original row.
pK2 PeriodStart ModifiedDate MaxModified myID PeriodEnd
3 2016-03-01 00:00:00.000 2016-04-01 00:00:00.000 1 1 2016-05-01 00:00:00.000
5 2016-05-01 00:00:00.000 2016-06-02 00:00:00.000 1 2 NULL
Once we have that, its a simple matter of joining on the start/end dates to get our pk2 value.
Full script...
DECLARE #Table1 TABLE (pK1 INT, PeriodStart DATETIME, pK2 INT)
DECLARE #Table2 TABLE (pK2 INT, PeriodStart DATETIME, ModifiedDate DATETIME)
INSERT INTO #Table1
VALUES (1,'2016-04-01',NULL),
(2,'2016-07-01',NULL)
INSERT INTO #Table2
VALUES (3,'2016-03-01','2016-04-01'),
(4,'2016-05-01','2016-06-01'),
(5,'2016-05-01','2016-06-02')
;WITH OrderedList AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY PeriodStart ORDER BY ModifiedDate DESC) AS MaxModified
FROM #Table2
),X AS
(
SELECT *,
ROW_NUMBER() OVER(ORDER BY PeriodStart) AS myID
FROM OrderedList
WHERE MaxModified=1
), Y AS
(
SELECT L.*, R.PeriodStart AS PeriodEnd
FROM X L
LEFT JOIN X R ON L.myID=R.myID-1 AND R.MaxModified=1
WHERE L.MaxModified=1
)
UPDATE T SET pK2=Y.pK2
FROM #Table1 T
LEFT JOIN Y ON T.PeriodStart >= Y.PeriodStart AND T.PeriodStart < COALESCE(Y.PeriodEnd,CURRENT_TIMESTAMP)
SELECT *
FROM #Table1
I have searched high and low for weeks now trying to find a solution to my problem.
As far as I can ascertain, my SQL Server version (2008r2) is a limiting factor on this but, I am positive there is a solution out there.
My problem is as follows:
A have a table with potential contiguous dates in the form of Customer-Status-DateStart-DateEnd-EventID.
I need to merge contiguous dates by customer and status - the status field can shift up and down throughout a customers pathway.
Some example data is as follows:
DECLARE #Tbl TABLE([CustomerID] INT
,[Status] INT
,[DateStart] DATE
,[DateEnd] DATE
,[EventID] INT)
INSERT INTO #Tbl
VALUES (1,1,'20160101','20160104',1)
,(1,1,'20160104','20160108',3)
,(1,2,'20160108','20160110',4)
,(1,1,'20160110','20160113',7)
,(1,3,'20160113','20160113',9)
,(1,3,'20160113',NULL,10)
,(2,1,'20160101',NULL,2)
,(3,2,'20160109','20160110',5)
,(3,1,'20160110','20160112',6)
,(3,1,'20160112','20160114',8)
Desired output:
Customer | Status | DateStart | DateEnd
---------+--------+-----------+-----------
1 | 1 | 2016-01-01| 2016-01-08
1 | 2 | 2016-01-08| 2016-01-10
1 | 1 | 2016-01-10| 2016-01-13
1 | 3 | 2016-01-13| NULL
2 | 1 | 2016-01-01| NULL
3 | 2 | 2016-01-09| 2016-01-10
3 | 1 | 2016-01-10| 2016-01-14
Any ideas / code will be greatly received.
Thanks,
Dan
Try this
DECLARE #Tbl TABLE([CusomerID] INT
,[Status] INT
,[DateStart] DATE
,[DateEnd] DATE
,[EventID] INT)
INSERT INTO #Tbl
VALUES (1,1,'20160101','20160104',1)
,(1,1,'20160104','20160108',3)
,(1,2,'20160108','20160110',4)
,(1,1,'20160110','20160113',7)
,(1,3,'20160113','20160113',9)
,(1,3,'20160113',NULL,10)
,(2,1,'20160101',NULL,2)
,(3,2,'20160109','20160110',5)
,(3,1,'20160110','20160112',6)
,(3,1,'20160112','20160114',8)
;WITH CTE
AS
(
SELECT CusomerID ,
Status ,
DateStart ,
COALESCE(DateEnd, '9999-01-01') AS DateEnd,
EventID,
ROW_NUMBER() OVER (ORDER BY CusomerID, EventID) RowId,
ROW_NUMBER() OVER (PARTITION BY CusomerID, Status ORDER BY EventID) StatusRowId FROM #Tbl
)
SELECT
A.CusomerID ,
A.Status ,
A.DateStart ,
CASE WHEN A.DateEnd = '9999-01-01' THEN NULL
ELSE A.DateEnd END AS DateEnd
FROM
(
SELECT
CTE.CusomerID,
CTE.Status,
MIN(CTE.DateStart) AS DateStart,
MAX(CTE.DateEnd) AS DateEnd
FROM
CTE
GROUP BY
CTE.CusomerID,
CTE.Status,
CTE.StatusRowId -CTE.RowId
) A
ORDER BY A.CusomerID, A.DateStart
Output
CusomerID Status DateStart DateEnd
----------- ----------- ---------- ----------
1 1 2016-01-01 2016-01-08
1 2 2016-01-08 2016-01-10
1 1 2016-01-10 2016-01-13
1 3 2016-01-13 NULL
2 1 2016-01-01 NULL
3 2 2016-01-09 2016-01-10
3 1 2016-01-10 2016-01-14
I have a table in which records are inserted at different periods (each record contains a column called 'Amount').
I want to show the total amount acummulation, after each 5 seconds. I have tried with the following query without success:
SELECT Sum(totalamount) AS RealTimeTotalAmount,
Datepart(second, createstamp) / 5 AS dp
FROM [order]
WHERE
createstamp BETWEEN Dateadd(s, -5, Getdate()) AND Getdate()
GROUP BY Datepart(second, createstamp) / 5
The problem I am facing is, that it shows me the 'accumulative sum as per each second' and I want to see it like '(accumulative sum as per each second + total accumulative amount till that second)'
Here is how the source data looks like:
-----------------------------------------------------------
|OrderID | CreateStamp | TotalAmount |
-----------------------------------------------------------
|1 |2015-03-22 15:26:05.620 | 10 |
-----------------------------------------------------------
|2 |2015-03-22 15:26:05.653 | 20 |
-----------------------------------------------------------
|3 |2015-03-22 15:26:05.660 | 10 |
-----------------------------------------------------------
|4 |2015-03-22 15:26:06.663 | 10 |
-----------------------------------------------------------
|5 |2015-03-22 15:26:06.670 | 30 |
-----------------------------------------------------------
Essentially, I want the resulting query to return as follows:
----------------------------------------
|Period | Accumulative Amount |
----------------------------------------
|0 to 5 seconds | 30 |
----------------------------------------
|0 to 10 seconds | 80 |
----------------------------------------
This is basically an accumulation from 0 time to multiples of 5.for last 5 seconds basically i am calculating the amount for the whole day up to the time when i execute this query and for example the amount for whole day before this time was 50 so result table should look like
----------------------------------------
|0 to 5 seconds | 30 + 50 = 80 |
----------------------------------------
|0 to 10 seconds | 80 + 80 = 160 |
----------------------------------------
you can try something like this.
Input Data
DECLARE #Orders TABLE
(
OrderId INT,
CreateStamp DATETIME,
TotalAmount NUMERIC(9,2)
)
INSERT INTO #Orders
SELECT 1,'2015-03-22 15:26:05.620',400
UNION ALL SELECT 2,'2015-03-22 15:26:04.653',500
UNION ALL SELECT 3,'2015-03-22 15:26:05.660',600
UNION ALL SELECT 4,'2015-03-22 15:26:06.663',700
UNION ALL SELECT 5,'2015-03-22 15:26:06.670',900
UNION ALL SELECT 6,'2015-03-22 15:26:05.660',600
UNION ALL SELECT 7,'2015-03-22 15:26:09.663',700
UNION ALL SELECT 8,'2015-03-22 15:26:12.670',900
Query
;WITH CTE as
(
SELECT DATEDIFF(minute,0,CreateStamp)totalminutes,Datepart(second, CreateStamp ) / 5 sec,SUM(TotalAmount) TotalAmount
FROM #Orders
GROUP BY DATEDIFF(minute,0,CreateStamp),Datepart(second, CreateStamp) / 5
)
SELECT DATEADD(minute,totalminutes,0) dt,sec,(SELECT SUM(TotalAmount) FROM cte WHERE totalminutes <=c2.totalminutes and sec <=c2.sec)
FROM CTE c2
ORDER BY sec;
I have added a GROUP BY DATEDIFF(minute,0,CreateStamp) to separate seconds for different dates and minutes.
If I understand you correctly:
DECLARE #t TABLE
(
ID INT ,
D DATETIME ,
A MONEY
)
DECLARE #mind DATETIME ,
#maxd DATETIME
INSERT INTO #t
VALUES ( 1, '2015-04-07 13:49:15.000', 5 ),
( 2, '2015-04-07 13:49:17.000', 15 ),
( 3, '2015-04-07 13:49:35.000', 2 ),
( 4, '2015-04-07 13:49:45.000', 4 ),
( 5, '2015-04-07 13:49:49.000', 20 ),
( 6, '2015-04-07 13:50:05.000', 20 ),
( 7, '2015-04-07 13:50:09.000', 3 ),
( 8, '2015-04-07 13:50:09.000', 3 ),
( 9, '2015-04-07 13:50:10.000', 1 ),
( 10, '2015-04-07 13:50:15.000', 1 )
SELECT #mind = MIN(d) ,
#maxd = MAX(d)
FROM #t;
WITH cte
AS ( SELECT #mind AS d
UNION ALL
SELECT DATEADD(ss, 5, d)
FROM cte
WHERE cte.d <= #maxd
)
SELECT cte.d, SUM(A) AS A FROM cte
JOIN #t t ON t.D < cte.d
GROUP BY cte.d
Output:
d A
2015-04-07 13:49:20.000 20.00
2015-04-07 13:49:25.000 20.00
2015-04-07 13:49:30.000 20.00
2015-04-07 13:49:35.000 20.00
2015-04-07 13:49:40.000 22.00
2015-04-07 13:49:45.000 22.00
2015-04-07 13:49:50.000 46.00
2015-04-07 13:49:55.000 46.00
2015-04-07 13:50:00.000 46.00
2015-04-07 13:50:05.000 46.00
2015-04-07 13:50:10.000 72.00
2015-04-07 13:50:15.000 73.00
2015-04-07 13:50:20.000 74.00