Impossible Task On Sql Calculation Where Date Is Equal - sql

**
LOOK AT MY ANSWER WHICH IS REFERE AS NEW QUESTION ON SAME PROBLEM.
**
I have Confusion against utilize If,Else Statement against calculation of stock By date. And sort the same by date.
There is real challenge to calculate running total between equal date:
If date is equal
If date is greater than
If date is less than
My Table Schema Is:
TransID int, Auto Increment
Date datetime,
Inwards decimal(12,2)
Outward decimal(12,2)
Suppose If I have Records as Below:
TransID Date(DD/MM/YYYY) Inward Outward
1 03/02/2011 100
2 12/04/2010 200
3 03/02/2011 400
Than Result Should be:
TransID Date(DD/MM/YYYY) Inward Outward Balance
2 12/04/2010 200 -200
1 03/02/2011 100 -300
3 03/02/2011 400 100
I wants to calculate Inward - outwards = Balance and Balance count as running total as above. but the condition that it should be as per date order by Ascending
How to sort and calculate it by date and transID?
What is transact SQL IN SQL_SERVER-2000**?.

You can use a brute O(n2) approach of self-joining the table to itself, or if the table is large, it is better to iteratively calculate the balance. The choices for SQL Server 2000 are limited, but the approach I will show uses a loop that traverses the table in date, transid order rather than using cursors.
Here is a sample table for discussion
create table trans (transid int identity, date datetime, inwards decimal(12,2), outward decimal(12,2))
insert trans select '20110203', null, 100
insert trans select '20100412', null, 200
insert trans select '20110203', 400, null -- !same date as first
This is the T-SQL batch that will give you the output you require. If you merely wanted to update a balance column in the table (if it had such an extra column), change all references to #trans to the table itself.
-- fill a temp table with the new column required
select *, cast(null as decimal(12,2)) as balance
into #trans
from trans
-- create an index to aid performance
create clustered index #cix_trans on #trans(date, transid)
-- set up a loop to go through all record in the temp table
-- in preference to using CURSORs
declare #date datetime, #id int, #balance decimal(12,2)
select top 1 #date = date, #id = transid, #balance = 0
from #trans
order by date, transid
while ##ROWCOUNT > 0 begin
update #trans set #balance = balance = #balance + coalesce(inwards, -outward)
where transid = #id
-- next record
select top 1 #date = date, #id = transid
from #trans
where (date = #date and transid > #id)
or (date > #date)
order by date, transid
end
-- show the output
select *
from #trans
order by date, transid
;
-- clean up
drop table #trans;
Output
2 2010-04-12 00:00:00.000 NULL 200.00 -200.00
1 2011-02-03 00:00:00.000 NULL 100.00 -300.00
3 2011-02-03 00:00:00.000 400.00 NULL 100.00
EDIT
If you need to show the final output using the date formatted to dd/mm/yyyy, use this
-- show the output
select transid, convert(char(10), date, 103) date, inwards, outward, balance
from #trans
order by #trans.date, transid
;

Is Balance (Inward-Outward) ?
select TransID,
Date,
Inward,
Outward,
(select sum(Inward - Outward)
from tbl_name b1
where b1.TransID <= b.TransID) as RunB
from tbl_name b
order by Date desc,TransID desc
This would order by Date in descending order - if the dates are same they are ordered by TransID
Edit:
Assume a Transaction table as this
select * from Transactions
1 NULL 100.00 2010-01-01 00:00:00.000
2 NULL 200.00 2010-01-02 00:00:00.000
3 400.00 NULL 2010-01-03 00:00:00.000
4 50.00 NULL 2010-01-03 00:00:00.000
5 NULL 100.00 2010-01-04 00:00:00.000
If you do this query ie, sort by TransactionIDs you would get this!
select TransID,
Date,
isNull(Inward,0.0),
isNull(Outward,0.0),
(select sum(isNull(Inward,0.0) - isNull(Outward,0.0))
from Transactions b1
where b1.TransID <= b.TransID) as RunB
from Transactions b
order by Date asc,TransID asc
1 2010-01-01 00:00:00.000 0.00 100.00 -100.00
2 2010-01-02 00:00:00.000 0.00 200.00 -300.00
3 2010-01-03 00:00:00.000 400.00 0.00 100.00
4 2010-01-03 00:00:00.000 50.00 0.00 150.00
5 2010-01-04 00:00:00.000 0.00 100.00 50.00
Instead if you use this query - sort by date you would get this? Is this what you meant Mahesh?
select TransID,
Date,
isNull(Inward,0.0),
isNull(Outward,0.0),
(select sum(isNull(Inward,0.0) - isNull(Outward,0.0))
from Transactions b1
where b1.Date <= b.Date) as RunB
from Transactions b
order by Date asc,TransID asc
1 2010-01-01 00:00:00.000 0.00 100.00 -100.00
2 2010-01-02 00:00:00.000 0.00 200.00 -300.00
3 2010-01-03 00:00:00.000 400.00 0.00 150.00
4 2010-01-03 00:00:00.000 50.00 0.00 150.00
5 2010-01-04 00:00:00.000 0.00 100.00 50.00
The difference in queries being -> (b1.Date <= b.Date) and (b1.TransID <= b.TransID)

Take this first bit of cyberkiwi's solution:
select *, cast(null as decimal(12,2)) as balance
into #trans
from stock
and change it so the nvarchar dates from your table are converted to datetime values. That is, expand the * into the actual set of columns, replacing the date column with the converting expression.
Given the structure you've shown in your original question, it may look like this:
select
TransID,
convert(datetime, substring(Date,7,4) + substring(Date,4,2) + substring(Date,1,2)) as Date,
Inward,
Outward,
cast(null as decimal(12,2)) as balance
into #trans
from stock
Leave the rest of the script untouched.

Now this is Solution with date in format dd/MM/yyyy of above question.
select *, cast(null as decimal(12,2)) as balance
into #trans
from stock
-- create an index to aid performance
create clustered index #cix_trans on #trans(date, transid)
--set up a loop to go through all record in the temp table
-- in preference to using CURSORs
declare #date datetime, #id int, #balance decimal(12,2)
select top 1 #date = date, #id = transid, #balance = 0
from #trans
order by date, transid
while ##ROWCOUNT > 0 begin
update #trans set #balance = balance = #balance + coalesce(input, -output)
where transid = #id
-- next record
select top 1 #date = date, #id = transid
from #trans
where (date = #date and transid > #id)
or (date > #date)
order by date, transid
end
-- show the output
select
transID,
date= convert(varchar,convert(datetime,date,103),103),
input,
output,
balance
from #trans
order by convert(datetime,date,103), transID
-- clean up
drop table #trans;

Related

TSQL order by group for monthly reports

I have court clearance statistic to made, but i have some slight problem with my monthly.. it didt follow in order, and wish someone could help me fix it.. and is it possible to add total in my table?
DECLARE #StartDate As date = '03-28-2015',
#EndDate As date = '03-28-2015'
DECLARE #TEMP_DATES AS TABLE (FROM_DATE DATE, TO_DATE DATE)
INSERT INTO #TEMP_DATES VALUES(#StartDate, #EndDate)
DECLARE #TENP_MONTH_YEAR AS TABLE(MONTH_YEAR VARCHAR(20), [YEAR] INT, [MONTH] INT)
INSERT INTO #TENP_MONTH_YEAR
select FORMAT(D.Dates, 'MMMM-yy', 'en-US' ) AS MonthYear, YEAR(D.Dates), MONTH(D.Dates)
from #TEMP_DATES as T
inner join master..spt_values as N
on N.number between 0 and datediff(DAY, T.FROM_DATE, T.TO_DATE)
cross apply (select dateadd(DAY, N.number, T.FROM_DATE)) as D(Dates)
where N.type ='P'
GROUP BY FORMAT(D.Dates, 'MMMM-yy', 'en-US' ), YEAR(D.Dates), MONTH(D.Dates)
ORDER BY YEAR(D.Dates), MONTH(D.Dates)
DECLARE #NEWID AS UNIQUEIDENTIFIER = NEWID()
SELECT CT.RPT_CASE_CODE_GROUP, SUM(ISNULL(INCOMING_CASES, 0)) AS INCOMING_CASES, SUM(ISNULL(OUTGOING_CASES, 0)) AS OUTGOING_CASES,
ISNULL(CAST(SUM(NULLIF(CAST(ISNULL(OUTGOING_CASES, 0) AS DECIMAL),0.00))/SUM(NULLIF(CAST(ISNULL(INCOMING_CASES, 0) AS DECIMAL),0.00)) * 100 AS DECIMAL(18,2)),0) AS [CLEARANCE_RATE],
MONTH_YEAR
FROM #tempClearanceListCases tempCLC
RIGHT OUTER JOIN (SELECT CASE_TYPE_ID, MONTH_YEAR, [YEAR], [MONTH]
FROM (SELECT DISTINCT CASE_TYPE_ID FROM #tempClearanceListCases tempCLC ) A, #TENP_MONTH_YEAR tempMonthYear) B
ON B.CASE_TYPE_ID = tempCLC.CASE_TYPE_ID AND tempCLC.MONTHLY = B.MONTH_YEAR
INNER JOIN CaseType CT WITH (NOLOCK)
ON B.CASE_TYPE_ID = CT.CASE_TYPE_ID
WHERE ISNULL(COURT_LOCATION_ID, #NEWID) = ISNULL(#COURT_LOCATION_ID, ISNULL(COURT_LOCATION_ID, #NEWID))
GROUP BY CT.RPT_CASE_CODE_GROUP, [INTERVAL_MONTH], MONTH_YEAR
ORDER BY CT.RPT_CASE_CODE_GROUP
The result which is the monthly is not correct order:
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 15 4 26.67 March-15
BCY/CP 15 0 0.00 February-15
BCY/CP 33 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
BCY/DP 1 0 0.00 January-15
The result atleast i want it to be :
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 33 0 0.00 January-15
BCY/CP 15 0 0.00 February-15
BCY/CP 15 4 26.67 March-15
BCY/DP 1 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
The result i want :
RPT_CASE_CODE_GROUP | INCOMEING CASES | OUTGOING CASES | CLEARANCERATE | MONTHYEAR
BCY/CP 33 0 0.00 January-15
BCY/CP 15 0 0.00 February-15
BCY/CP 15 4 26.67 March-15
63 4 6.34 Overall
BCY/DP 1 0 0.00 January-15
BCY/DP 0 0 0.00 February-15
BCY/DP 2 0 0.00 March-15
3 0 0.00 Overall
DO i have to stick to my query or create grouping query? i already spend many hour on this, i feel hard to turn back, im fresh grad :( can any guru guide me?
if all your MONTHYEAR are following the sames patter monthname-xx you can use following statement on order:
ORDER BY
cast('20' + substring(MONTHYEAR, Charindex('-', MONTHYEAR) + 1, 2) + '-' + substring(MONTHYEAR, 1, 3) + '-01' AS date)
This looks like a job for the UNION clause. It seems like you should have this execution order for the results you want:
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
UNION ALL
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = 'BCY/DP'
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = 'BCY/CP'
Alternatively, if there are more RPT_CASE_CODE_GROUP values than the one presented, you can use a loop to capture information about all of them like this:
CREATE TABLE #rccg(ID INT IDENTITY(1,1), RPT_CASE_CODE_GROUP NVARCHAR(15))
INSERT INTO #rccg(RPT_CASE_CODE_GROUP)
SELECT DISTINCT RPT_CASE_CODE_GROUP FROM --data source
DECLARE #i INT = 1, #j INT = (SELECT MAX(ID) FROM #rccg), #rccg NVARCHAR(15)
DECLARE #results TABLE(rccg NVARCHAR(15), ic INT, oc INT, cr INT, my NVARCHAR(20))
WHILE #i < #j
BEGIN
SET #rccg = (SELECT RPT_CASE_CODE_GROUP FROM #rccg WHERE ID = #i)
INSERT INTO #results
SELECT -- data you want from tables w/ all joins
WHERE RPT_CASE_CODE_GROUP = #rccg
UNION ALL
SELECT '', SUM([INCOMING CASES]), SUM([OUTGOING CASES]), AVG([CLEARANCE RATE], 'Overall'
FROM -- source data
WHERE RPT_CASE_CODE_GROUP = #rccg
END
SELECT * FROM #rccg
DROP TABLE #rccg
I know I didn't use your specific code, because that would have taken up a huge amount of space, but I think you get the general idea. For each field you want the totals of for the time period, you use the SUM(column_name) aggregate function. You can get a pretty good explanation and examples here: http://www.techonthenet.com/sql/sum.php.
I hope this at least helps point you in the right direction.

Contiguous Dates

Here is the table that I am working with:
MemberID MembershipStartDate MembershipEndDate
=================================================================
123 2010-01-01 00:00:00.000 2012-12-31 00:00:00.000
123 2011-01-01 00:00:00.000 2012-12-31 00:00:00.000
123 2013-05-01 00:00:00.000 2013-12-31 00:00:00.000
123 2014-01-01 00:00:00.000 2014-12-31 00:00:00.000
123 2015-01-01 00:00:00.000 2015-03-31 00:00:00.000
What I want is to create one row that shows continuous membership,
and a second row if the membership breaks by more than 2 days, with a new start and end date..
So the output I am looking for is like:
MemberID MembershipStartDate MembershipEndDate
=================================================================
123 2010-01-01 00:00:00.000 2012-12-31 00:00:00.000
123 2013-05-01 00:00:00.000 2015-03-31 00:00:00.000
There is a memberID field attached to these dates which is how they are grouped.
I've had to deal with this kind of thing before
I use something like this
USE tempdb
--Create test Data
DECLARE #Membership TABLE (MemberID int ,MembershipStartDate date,MembershipEndDate date)
INSERT #Membership
(MemberID,MembershipStartDate,MembershipEndDate)
VALUES (123,'2010-01-01','2012-12-31'),
(123,'2011-01-01','2012-12-31'),
(123,'2013-05-01','2013-12-31'),
(123,'2014-01-01','2014-12-31'),
(123,'2015-01-01','2015-03-31')
--Create a table to hold all the dates that might be turning points
DECLARE #SignificantDates Table(MemberID int, SignificantDate date, IsMember bit DEFAULT 0)
--Populate table with the start and end dates as well as the days just before and just after each period
INSERT #SignificantDates (MemberID ,SignificantDate)
SELECT MemberID, MembershipStartDate FROM #Membership
UNION
SELECT MemberID,DATEADD(day,-1,MembershipStartDate ) FROM #Membership
UNION
SELECT MemberID,MembershipEndDate FROM #Membership
UNION
SELECT MemberID,DATEADD(day,1,MembershipEndDate) FROM #Membership
--Set the is member flag for each date that is covered by a membership
UPDATE sd SET IsMember = 1
FROM #SignificantDates sd
JOIN #Membership m ON MembershipStartDate<= SignificantDate AND SignificantDate <= MembershipEndDate
--To demonstrate what we're about to do, Select all the dates and show the IsMember Flag and the previous value
SELECT sd.MemberID, sd.SignificantDate,sd.IsMember, prv.prevIsMember
FROM
#SignificantDates sd
JOIN (SELECT
MemberId,
SignificantDate,
IsMember,
Lag(IsMember,1) OVER (PARTITION BY MemberId ORDER BY SignificantDate desc) AS prevIsMember FROM #SignificantDates
) as prv
ON sd.MemberID = prv.MemberID
AND sd.SignificantDate = prv.SignificantDate
ORDER BY sd.MemberID, sd.SignificantDate
--Delete the ones where the flag is the same as the previous value
delete sd
FROM
#SignificantDates sd
JOIN (SELECT MemberId, SignificantDate,IsMember, Lag(IsMember,1) OVER (PARTITION BY MemberId ORDER BY SignificantDate) AS prevIsMember FROM #SignificantDates ) as prv
ON sd.MemberID = prv.MemberID
AND sd.SignificantDate = prv.SignificantDate
AND prv.IsMember = prv.prevIsMember
--SELECT the Start date for each period of membership and the day before the following period of non membership
SELECT
nxt.MemberId,
nxt.SignificantDate AS MembershipStartDate,
DATEADD(day,-1,nxt.NextSignificantDate) AS MembershipEndDate
FROM
(
SELECT
MemberID,
SignificantDate,
LEAd(SignificantDate,1) OVER (PARTITION BY MemberId ORDER BY SignificantDate) AS NextSignificantDate,
IsMember
FROM #SignificantDates
) nxt
WHERE nxt.IsMember = 1

An attempt to create a balance between debit and credit

Well, I'll go directly to the case that is presented to me when trying to make a book with Extract and MUST HAVE in continuous BALANCE.
I was really hanging in my consultation, and I can not find any solution for desired.
Thanked would in some small contribution to some of you.
I'm looking for something like this:
ACCDATE ACCOUNT DEBIT CREDIT BALANCE
2013-01-01 00:00:00 11200 0.00 1500.00 -1500.00
2013-01-01 00:00:00 11200 0.00 60.00 -1560.00
2013-01-01 00:00:00 11200 0.00 400.00 -1960.00
2013-01-01 00:00:00 11200 0.00 100.00 -2060.00
2013-01-01 00:00:00 11200 0.00 300.00 -2360.00
2013-01-01 00:00:00 11200 0.00 250.00 -2910.00
OR:
ACCDATE ACCOUNT DEBIT CREDIT BALANCE
2013-01-01 00:00:00 11200 1500.00 0 1500.00
2013-01-01 00:00:00 11200 0.00 60.00 1440.00
2013-01-01 00:00:00 11200 0.00 400.00 1040.00
2013-01-01 00:00:00 11200 0.00 40 1000.00
2013-01-01 00:00:00 11200 300 0 1300.00
2013-01-01 00:00:00 11200 0.00 250.00 1550.00
I really do not require account type filter it by this time, but specific.
The idea is that with my Query still does not give me that result.
They can buy creating a provisional or temporary table with the same shown below:
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110101','D',11200,1500)
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110101','C',11200,60)
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110102','D',11200,400)
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110102','C',11200,100)
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110102','C',11200,300)
INSERT INTO Accounting (AccDate,DebitCredit,Account,Amount) VALUES ('20110102','C',11200,250)
WITH CTE_FIRST AS
(
SELECT ACCDATE,
ACCOUNT,
CASE WHEN DEBITCREDIT='D' THEN AMOUNT ELSE 0 END AS DEBIT,
CASE WHEN DEBITCREDIT='C' THEN AMOUNT ELSE 0 END AS CREDIT,
ROW_NUMBER()OVER(ORDER BY ACCOUNT,ACCDATE) RN
FROM ACCOUNTING
WHERE ACCDATE >='20130101'
)
,CTE_SECOND AS(
SELECT *,
ISNULL((SELECT TOP 1 DEBIT FROM CTE_FIRST B WHERE B.ACCOUNT=A.ACCOUNT AND B.RN<A.RN ORDER BY RN DESC),0) COL1,
ISNULL((SELECT TOP 1 CREDIT FROM CTE_FIRST B WHERE B.ACCOUNT=A.ACCOUNT AND B.RN<A.RN ORDER BY RN DESC),0) COL2
FROM CTE_FIRST A
)
SELECT ACCDATE,ACCOUNT,DEBIT,CREDIT,
CASE WHEN DEBIT=0 THEN 0-(CREDIT+COL2) ELSE DEBIT+COL1 END BALANCE
FROM CTE_SECOND
Something happens in the validation of sum or not it's taking so linear consulting ....
All of this inquiry, I tried to help me with material that I got on the web. But it gives me the total response.
In the end I got this solution, but it becomes very slow the process.
Is there a way to optimize it?
Very slow for real, and it does not work for high queries.
DECLARE #T TABLE( FECHA DATETIME, COMENTARIO NVARCHAR (300), CUENTA
VARCHAR(15), DEBE NUMERIC(15,2), HABER NUMERIC(15,2) )
INSERT INTO #T SELECT FECHA, COMENTARIO, CUENTA, DEBE, HABER FROM
DIARIOAPUNTES;
/* INSERT INTO #T VALUES ('001-0001','20130102',100,0); INSERT INTO #T
VALUES ('001-0001','20130102',0,200); INSERT INTO #T VALUES
('001-0001','20130102',100,0); INSERT INTO #T VALUES
('001-0001','20130103',100,0); INSERT INTO #T VALUES
('001-0001','20130105',0,100); INSERT INTO #T VALUES
('001-0002','20130105',100,0); INSERT INTO #T VALUES
('001-0002','20130106',500,0);
*/
--DEBIT - CREDIT + BALANCE
WITH T_ROW AS (
SELECT (ROW_NUMBER() OVER(ORDER BY (T1_1.FECHA) ASC)) AS CONTADOR, FECHA, T1_1.CUENTA, T1_1.COMENTARIO, T1_1.DEBE, T1_1.HABER
FROM #T T1_1 )
SELECT T1.CONTADOR, T1.CUENTA, T1.COMENTARIO AS DESCRIPCION,
Convert(CHAR(10), T1.FECHA, 103) AS FECHA, T1.DEBE, T1.HABER,
ROUND(T1.DEBE-T1.HABER + COALESCE(T2.SALDO,0),2) AS SALDO FROM T_ROW
T1
CROSS APPLY(
SELECT ROUND(SUM(DEBE)-SUM(HABER),2) AS SALDO
FROM T_ROW T2
WHERE T2.CONTADOR < T1.CONTADOR AND T1.CUENTA = T2.CUENTA
) AS T2
--WHERE T1.FECHA BETWEEN '20130101' AND '20131231'
ORDER BY T1.CUENTA, T1.FECHA
--WHERE T1.ACCOUNTNO = '001-0001'

Convert Date Range to Individual Days

A table called VolumeRequest stores the volume requests by accounts for a date range.
AccountId StartDate EndDate DailyVolume
670 2013-07-01 00:00:00.000 2013-07-31 00:00:00.000 10
670 2013-07-01 00:00:00.000 2013-07-31 00:00:00.000 1050
670 2013-07-10 00:00:00.000 2013-07-10 00:00:00.000 -350
670 2013-07-24 00:00:00.000 2013-07-26 00:00:00.000 -350
673 2013-06-01 00:00:00.000 2013-07-31 00:00:00.000 233
I need to display the requests on daily basis where volume is summed by day by account for a given date range like for month of July the report is like below. The date start and end dates of the volume requests need to be trimmed for the given report dates
AccountId Date Volume
670 2013-07-01 00:00:00.000 1060
670 2013-07-02 00:00:00.000 1060
.
.
670 2013-07-10 00:00:00.000 710
.
.
670 2013-07-24 00:00:00.000 710
670 2013-07-25 00:00:00.000 710
670 2013-07-26 00:00:00.000 710
.
.
670 2013-07-31 00:00:00.000 1060
673 2013-07-01 00:00:00.000 233
.
.
673 2013-07-31 00:00:00.000 233
Right now I am using table Variables and loops to achieve it which I know is not a good way to code.
DECLARE #sDate DATETIME, #eDate DATETIME , #volume DECIMAL (10, 4), rstartdate DATETIME, #renddate DATETIME , #loopcount INT
SET #sdate = '4/1/2013'
SET #edate = '4/30/2013'
DECLARE #VolumeRequest TABLE
(
ID INT IDENTITY (1, 1) PRIMARY KEY,
Aid INT,
Startdate DATETIME,
Enddate DATETIME,
volume DECIMAL (14, 4)
)
DECLARE #DailyRequest TABLE
(
ID INT IDENTITY (1, 1) PRIMARY KEY,
Accountid INT,
ReadDate DATETIME,
Volume DECIMAL (14, 4)
)
INSERT INTO #VolumeRequest
SELECT Accountid,
( CASE
WHEN #sdate > startdate THEN #sdate
ELSE startdate
END ),
( CASE
WHEN #edate < enddate THEN #edate
ELSE enddate
END ),
dailyvolume
FROM VolumeRequest
WHERE Startdate <= #edate
AND Enddate >= #sdate
AND isnull (deprecated, 0) != 1
--loop to breakdown the volume requests into daily requests
SET #loopcount = 1
WHILE #loopcount <= (SELECT MAX(ID)
FROM #VolumeRequest)
BEGIN
SELECT #volume = volume,
#rstartdate = Startdate,
#renddate = Enddate
FROM #VolumeRequest
WHERE ID = #loopcount
WHILE #rstartdate <= #renddate
BEGIN
INSERT INTO #DailyRequest
SELECT #currentaid,
#rstartdate,
#volume
SET #rstartdate = DATEADD(day, 1, #rstartdate)
END
SET #LoopCount = #LoopCount + 1
END
I am looking for ways which don't involve loops or cursors. I found a Similar Question. The answers there didn't help me.
I like to use a Dates table such as
CREATE TABLE #Dates(
DateId INT,
CalendarDate DATETIME)
filled with dates for whatever range you need. I use this table to join to tables such as VolumeRequest to retrieve the output you requested.
SELECT
v.AccountId,
d.CalendarDate,
SUM(v.DailyVolume)
FROM
#Dates d INNER JOIN
VolumeRequest v ON
d.CalendarDate >= v.StartDate AND
d.CalendarDate <= v.EndDate
group by
d.CalendarDate,
v.AccountId
to fill the #Dates table, I use something like this:
declare #startdate datetime = '6/1/13', #enddate datetime = '7/31/13'
create table #Dates(CalendarDate datetime)
insert into #Dates(CalendarDate)
select
dateadd(dd, rid-1, #startdate) as calendardate
from (
select
ROW_NUMBER() over(order by o.object_id) as rid
From
sys.objects o cross apply
sys.objects o2
) dates
where
dateadd(dd, rid-1, #startdate) >= #startdate and dateadd(dd, rid-1, #startdate) <= #enddate
Modify to meet your date range needs.
SQLFiddle demo
Using WITH clause and recursion we generate Days table with all days between MIN and MAX dates.
Then generate table Accounts with distinct AccountID.
Finally JOIN all these tables and group all with SUM.
WITH MINMAX as
( SELECT MIN(StartDate) as MinDate,
MAX(EndDate) as MaxDate
from T
),
DAYS as
( SELECT MinDate as D from MINMAX
UNION ALL
SELECT D+1 as D FROM DAYS WHERE D+1<=
(
SELECT MaxDate FROM MINMAX
)
),
Accounts as
(
select distinct AccountID from T
)
select A.AccountId,Days.D,sum(T.DailyVolume) from Days
CROSS JOIN Accounts A
JOIN T on A.AccountID=T.AccountID
AND
Days.D between T.StartDate and T.EndDate
GROUP BY A.AccountId,Days.D
ORDER BY A.AccountId,Days.D
OPTION (MAXRECURSION 10000)

Running Total on date column

I have the following data in my table:
id invoice_id date ammount
1 1 2012-01-01 100.00
20 1 2012-01-31 50.00
470 1 2012-01-15 300.00
Now, I need to calculate running total for an invoice in some period. So, the output for this data sample should look like this:
id invoice_id date ammount running_total
1 1 2012-01-01 100.00 100.00
470 1 2012-01-15 300.00 400.00
20 1 2012-01-31 50.00 450.00
I tried with this samples http://www.sqlusa.com/bestpractices/runningtotal/ and several others, but the problem is that I could have entries like id 20, date 2012-01-31 and id 120, date 2012-01-01, and then I couldn't use NO = ROW_NUMBER(over by date)... in first select and then ID < NO in second select for calculating running total.
DECLARE #DateStart DATE='2012-01-01';
WITH cte
AS (SELECT id = Row_number() OVER(ORDER BY [date]),
DATE,
myid = id,
invoice_id,
orderdate = CONVERT(DATE, DATE),
ammount
FROM [Table_2]
WHERE DATE >= #DateStart)
SELECT myid,
invoice_id,
DATE,
ammount,
runningtotal = (SELECT SUM(ammount)
FROM cte
WHERE id <= a.id)
FROM cte AS a
ORDER BY id