TSQL order by group for monthly reports - sql

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.

Related

sql server allocate payment to items

I have been scratching my head with this one for an hour still cannot seem to figure out a way to allocate Payment amount of $30 to the rows in the following table.
Given that i have the following items. Negative amount means the customer is in debt and owes us that amount. Now given that customer pays $30. We need to allocate that to the item.
ItemId amount sDATE
BD98E890-C7F8-47F4-9125-A68A88DD178D -10 2016-01-04 00:00:00.000
7E047DE6-0DB7-4EDB-A751-C43BBD4610E5 -20 2016-01-05 00:00:00.000
5004AE1F-2A15-47E5-96FF-69A6C7D35521 -10 2016-01-06 00:00:00.000
for a payment of $30 the output should look like.
itemId BeforeAllocation AfterAllocation LeftToAllocate sDate
BD98E890-C7F8-47F4-9125-A68A88DD178D -10 0 30 2016-01-04 00:00:00.000
7E047DE6-0DB7-4EDB-A751-C43BBD4610E5 -20 0 20 2016-01-05 00:00:00.000
5004AE1F-2A15-47E5-96FF-69A6C7D35521 -10 -10 0 2016-01-06 00:00:00.000
and if customer is paying partial amount for exmaple $25 the output should be.
itemId BeforeAllocation AfterAllocation LeftToAllocate sDate
BD98E890-C7F8-47F4-9125-A68A88DD178D -10 0 25 2016-01-04 00:00:00.000
7E047DE6-0DB7-4EDB-A751-C43BBD4610E5 -20 -5 15 2016-01-05 00:00:00.000
5004AE1F-2A15-47E5-96FF-69A6C7D35521 -10 -10 0 2016-01-06 00:00:00.000
Code:
Create table #temp(ItemId UNIQUEIDENTIFIER , amount INT, sDATE DATETIME)
INSERT INTO #temp
( ItemId,
amount,
sDATE )
VALUES ( NEWID(),-10,'2016-01-04' ),
( NEWID(),-20,'2016-01-05' ),
( NEWID(),-10,'2016-01-06' )
SELECT * FROM (
SELECT 'BD98E890-C7F8-47F4-9125-A68A88DD178D' itemId, -10 BeforeAllocation, 0 AfterAllocation, 30 LeftToAllocate, '2016-01-04 00:00:00.000' sDate
UNION
SELECT '7E047DE6-0DB7-4EDB-A751-C43BBD4610E5' itemId, -20 BeforeAllocation, 0 AfterAllocation, 20 LeftToAllocate, '2016-01-05 00:00:00.000' sDate
UNION
SELECT '5004AE1F-2A15-47E5-96FF-69A6C7D35521' itemId, -10 BeforeAllocation, -10 AfterAllocation,0 LeftToAllocate, '2016-01-06 00:00:00.000' sDate
)s
ORDER BY sdate
SELECT * FROM (
SELECT 'BD98E890-C7F8-47F4-9125-A68A88DD178D' itemId, -10 BeforeAllocation, 0 AfterAllocation, 25 LeftToAllocate, '2016-01-04 00:00:00.000' sDate
UNION
SELECT '7E047DE6-0DB7-4EDB-A751-C43BBD4610E5' itemId, -20 BeforeAllocation, -5 AfterAllocation, 15 LeftToAllocate, '2016-01-05 00:00:00.000' sDate
UNION
SELECT '5004AE1F-2A15-47E5-96FF-69A6C7D35521' itemId, -10 BeforeAllocation, -10 AfterAllocation,0 LeftToAllocate, '2016-01-06 00:00:00.000' sDate
)s
ORDER BY sdate
Calculate an expression BeforeAllocationRT, to record the running total of BeforeAllocation (i.e. the sum of BeforeAllocation for this row and all preceding rows). If you're using SQL Server 2012 or later you can use window functions, otherwise you need a clumsy subexpression - see this question for exact instructions.
Calculate an expression for the amount to allocate
SELECT Allocation = CASE
WHEN BeforeAllocationRT + #Payment > 0
-- pay full amount for this item
THEN -#BeforeAllocation
WHEN BeforeAllocationRT + #Payment > #BeforeAllocation
-- pay partial amount for this item
THEN -(#BeforeAllocationRT+#Payment)
ELSE
-- pay nothing for this item
0
END
, ...
Calculate expressions for AfterAllocation and LeftToAllocate.
SELECT
AfterAllocation = BeforeAllocation + Allocation
,LeftToAllocate = CASE WHEN BeforeAllocationRT+#Payment>0 THEN #Payment-BeforeAllocationRT ELSE 0 END
,...
Combine steps 1,2,3 using CTEs or subexpressions.
Disclaimer: I don't have access to a SQL Server instance right now, so none of this is tested.
try this,
DECLARE #PaidAmout INT = 30
;WITH CTE AS
(
SELECT ItemId, amount, sDATE, ROW_NUMBER() OVER(ORDER BY sDATE) AS RowNo
FROM #temp
),
Amount AS
(
SELECT ItemId,
RowNo,
amount AS BeforeAllocation,
0 AS AfterAllocation,
#PaidAmout AS LeftToAllocate,
sDATE,
#PaidAmout + Amount AS LeftAmount
FROM CTE
WHERE RowNo = 1
UNION ALL
SELECT c.ItemId,
c.RowNo,
c.amount AS BeforeAllocation,
CASE WHEN a.LeftAmount + c.Amount < 0 THEN a.LeftAmount + c.Amount ELSE 0 END AS AfterAllocation,
CASE WHEN a.LeftAmount < 0 THEN 0 ELSE a.LeftAmount END AS LeftToAllocate,
c.sDATE,
a.LeftAmount + c.Amount AS LeftAmount
FROM CTE c
INNER JOIN Amount a ON a.RowNo + 1 = c.RowNo
)
SELECT ItemId,
BeforeAllocation,
AfterAllocation,
LeftToAllocate,
sDATE
FROM Amount

SQL See Whether Two or More Columns In a Table is Greater Than 0

I have ran in to a little problem and would appreciate any help.
My Table is such:
CASH | CREDIT CARD | DEBIT CARD | ACCOUNT | OTHER
-------------------------------------------------
0.00 0.00 0.00 0.00 0.00
1.00 0.00 0.00 0.00 0.00
2.00 1.00 0.00 0.00 0.00
My aim is to SELECT * FROM any of the above rows that have more than one column > 0.
So the third row would be selected in this scenario with the above table.
SELECT
[CASH], [CREDIT CARD], [DEBIT CARD], [ACCOUNT], [OTHER]
FROM table
WHERE
CASE WHEN [CASH] > 0 THEN 1 ELSE 0 END+
CASE WHEN [CREDIT CARD] > 0 THEN 1 ELSE 0 END+
CASE WHEN [DEBIT CARD] > 0 THEN 1 ELSE 0 END+
CASE WHEN [ACCOUNT] > 0 THEN 1 ELSE 0 END+
CASE WHEN [OTHER] > 0 THEN 1 ELSE 0 END >= 2
I prefer t-clausen's answer but just as an exercise, I decide to try it as an UNPIVOT followed by a PIVOT, so that we could write it using more of the general SQL tools:
declare #t table (SomeID int,Cash money,Credit money,Debit money,Account money,Other money)
insert into #t(SomeID,Cash,Credit,Debit,Account,Other) values
(1,0.00,0.00,0.00,0.00,0.00),
(2,1.00,0.00,0.00,0.00,0.00),
(3,2.00,1.00,0.00,0.00,0.00)
;With Unpiv as (
select *,SUM(CASE WHEN MoneyValue > 0.00 THEN 1 ELSE 0 END) OVER (PARTITION BY SomeID) as cnt
from #t t
unpivot (MoneyValue for MoneyType in (Cash,Credit,Debit,Account,Other)) x
), Repiv as (
select *
from Unpiv u
pivot (SUM(MoneyValue) for MoneyType in (Cash,Credit,Debit,Account,Other)) x
where
cnt >= 2
)
select * from Repiv
This does assume that you've got another column (here, called SomeID) by which each row can be uniquely identified.
Result:
SomeID cnt Cash Credit Debit Account Other
----------- ----------- --------------------- --------------------- --------------------- --------------------- ---------------------
3 2 2.00 1.00 0.00 0.00 0.00
Just hoping the above might be more adaptable for some variants of the requirements.
SELECT
[CASH], [CREDIT CARD], [DEBIT CARD], [ACCOUNT], [OTHER]
FROM table
WHERE (
SELECT COUNT(*)
FROM (VALUES ([CASH]),([CREDIT CARD]),([DEBIT CARD]),([ACCOUNT]),([OTHER])) t(value)
WHERE value > 0
) >= 2

aggregating data to getting running total

I have a query which outputs the below
I need to get it to provide a running total so for March it would give whats been paid in Feb and Mar, then for April Feb,Mar & Apr and so on.
Never come across needing this kind of aggregation before in SQL.
select
[monthid],
[month],
( select sum([paid]) from tbl t2 where t2.[monthid] <= t1.[monthid] ) as paid
from tbl t1
SELECT
T.MonthId
,T.[Month]
,T.Value
,RT.runningTotal
from Table_Name T
CROSS APPLY
(
SELECT SUM(value) as runningTotal
FROM Table_Name
WHERE MonthId <= T.MonthId
) as RT
order by T.MonthId
Test Data
declare #t1 TABLE (Monthid int, month varchar(10), Value decimal(18,2))
insert into #t1
values
(1,'JAN-13',35.00)
,(2, 'FEB-13',35.00)
,(3,'MAR-13',35.00)
,(4,'APR-13',35.00)
,(5,'JUN-13',35.00)
,(6,'Jul-13',35.00)
,(7,'Aug-13',35.00)
SELECT
T.MonthId
,T.[Month]
,T.Value
,RT.runningTotal
from #t1 T
CROSS APPLY
(
SELECT SUM(value) as runningTotal
FROM #t1
WHERE MonthId <= T.MonthId
) as RT
order by T.MonthId
RESULTS
MonthId Month Value runningTotal
1 JAN-13 35.00 35.00
2 FEB-13 35.00 70.00
3 MAR-13 35.00 105.00
4 APR-13 35.00 140.00
5 JUN-13 35.00 175.00
6 Jul-13 35.00 210.00
7 Aug-13 35.00 245.00
You can check this question and my answer on it. Turns out that recursive common table expression is the fastest method to get running total in SQL Server < 2012.
So in your case it could be something like:
with cte as
(
select T.MonthID, T.Month, T.Paid, T.Paid as Running_Paid
from Table1 as T
where T.MonthID = 118
union all
select T.MonthID, T.Month, T.Paid, T.Paid + C.Running_Paid as Running_Paid
from cte as C
inner join Table1 as T on T.MonthID = C.MonthID + 1
)
select *
from cte
option (maxrecursion 0)
Running totals in 2008 are kind of a pain. SQL Fiddle seems to have gone MIA again, but here's a simplistic example of how you can do it.
declare #t1 TABLE
(monthid int,
mth varchar(10),
paid decimal(18,2),
running_paid decimal(18,2))
insert into #t1
values (1,'JAN-13',35.00,0)
,(2, 'FEB-13',35.00,0)
,(3,'MAR-13',35.00,0)
declare #running decimal(18,2)
set #running= 0
update #t1 set running_paid = #running, #running= #running+ paid
select
*
from
#t1
Which will give you:
ID MTH PAID RUNNING_PAID
1 JAN-13 35.00 35.00
2 FEB-13 35.00 70.00
3 MAR-13 35.00 105.00
EDIT:
As Bogdan Sahlean points out, this is a very funky little process. You could also use a cursor:
declare #t1 TABLE
(monthid int,
mth varchar(10),
paid decimal(18,2)
)
insert into #t1
values (1,'JAN-13',35.00)
,(2, 'FEB-13',35.00)
,(3,'MAR-13',35.00)
declare #running table
(monthid int,
mth varchar(10),
paid decimal(18,2),
running_paid decimal(18,2))
declare c cursor
for select monthid,mth,paid from #t1
open c
declare #Id int
declare #Mth varchar(10)
declare #paid decimal(18,2)
declare #Running_Total decimal(18,2)
set #Running_Total = 0
fetch next from c
into #Id,#Mth,#paid
WHILE ##FETCH_STATUS = 0
begin
fetch next from c
into #Id,#Mth,#paid
select #Running_Total = #Running_Total + #paid --Here's this version's hack for running total
insert into #running values (#Id,#Mth,#paid,#Running_Total)
end
select
*
from
#running
They all kind of stink. This is a lot easier in SQL 2012.

Displaying weeks as columns

Below is the script to display the number of weeks between the given dates.
SET DATEFIRST 1
SELECT ta.account, ta.customer, SUM(amount), DATEPART(ww,ta.dt) WeekNumber
FROM tablename ta
WHERE dt >= '12/01/2011 00:00:00'
and dt < '12/29/2011 00:00:00'
GROUP BY ta.account, ta.customer, DATEPART(ww,ta.dt)
How do I display the diff weeks as diff columns in my result. Any suggestion would be helpful.
Sample O/P for the above is:
Date Account Customer TotalSeconds Amount WeekNumber
2011-11-01 xx0918252 198303792R 394 2.99 45
2011-11-08 xx1006979 200100567G 92 0.16 46
2011-11-15 xx1005385 A6863744I 492 1.275 47
2011-11-21 xx1012872 D7874694G 770 0.52 48
2011-11-28 xx1006419 C7112151H 1904 2.64 49
2011-11-28 xx1006420 G7378945A 77 0.3 49
I want the O/P like:
Date Account Customer TotalSeconds Amount WeekNumber45 WeekNumber46 WeekNumber47 WeekNumber8 WeekNumber49
and their corresponding data. Hope u understand my question. Thanks in advance.
Hi All, Thanks for the suggestions n help. Finally, I got the results that i wanted for time being. I still believe that it is hard coding. Is there a better solution for this. Thanks in advance. My code is as follows:
SELECT ta.account, ta.customer,
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '49' THEN amount END),0) AS "Week49",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '50' THEN amount END),0) AS "Week50",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '51' THEN amount END),0) AS "Week51",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '52' THEN amount END),0) AS "Week52",
isnull(SUM(CASE WHEN DATEPART(ww,ta.dt) = '53' THEN amount END),0) AS "Week53",
FROM (
select * from tablename
where dt >= '12/01/2011 00:00:00' and dt <= '12/31/2011 00:00:00'
) ta
group by ta.account, ta.customer
First of all I would put your result in temporary table for later calculations. Let's imagine that following CTE is your result:
if object_id('tempdb..#tab') is not null drop table #tab
;with cte (Date,Account,Customer,TotalSeconds,Amount,WeekNumber) as (
select cast('20111101' as datetime),'xx0918252','198303792R',394,2.99,45 union all
select '20111108','xx1006979','200100567G',92,0.16,46 union all
select '20111115','xx1005385','A6863744I',492,1.275,47 union all
select '20111121','xx1012872','D7874694G',770,0.52,48 union all
select '20111128','xx1006419','C7112151H',1904,2.64,49 union all
select '20111128','xx1006420','G7378945A',77,0.3,49
)
select * into #tab from cte
Now your computed data is in #tab table and the following query returns pivoted table for those weeknumbers:
select date, account, customer, totalSeconds, amount, [45], [46], [47], [48], [49] from
(
select date, account, customer, totalSeconds, amount, weeknumber as weeknumber from #tab
) src
pivot
(
max(weeknumber) for weekNumber in ([45], [46], [47], [48], [49])
) pvt
Dynamic version of this query might look like this:
declare #sql nvarchar(max), #cols varchar(max)
select #cols = coalesce(#cols + ',', '') + '[' + cast(weeknumber as varchar) + ']'
from (select distinct weeknumber from #tab) t
order by weeknumber
set #sql = N'
select date, account, customer, totalSeconds, amount, ' + #cols + ' from
(
select date, account, customer, totalSeconds, amount, weeknumber as weeknumber from #tab
) src
pivot
(
max(weeknumber) for weekNumber in (' + #cols + ')
) pvt
'
exec sp_executesql #sql
The result (in both cases):
date account customer totalSeconds amount 45 46 47 48 49
----------------------- --------- ---------- ------------ ---------- ------ ------ ------ ------ ------
2011-11-01 00:00:00.000 xx0918252 198303792R 394 2.990 45 NULL NULL NULL NULL
2011-11-08 00:00:00.000 xx1006979 200100567G 92 0.160 NULL 46 NULL NULL NULL
2011-11-15 00:00:00.000 xx1005385 A6863744I 492 1.275 NULL NULL 47 NULL NULL
2011-11-21 00:00:00.000 xx1012872 D7874694G 770 0.520 NULL NULL NULL 48 NULL
2011-11-28 00:00:00.000 xx1006419 C7112151H 1904 2.640 NULL NULL NULL NULL 49
2011-11-28 00:00:00.000 xx1006420 G7378945A 77 0.300 NULL NULL NULL NULL 49
Take a look at the PIVOT function.
Tsql pivot command
T-SQL Pivot function combined with dynamic SQL. Examples:
SQL Server 2005 Pivot on Unknown Number of Columns.
Pivots with Dynamic Columns in SQL Server 2005/2008.

Impossible Task On Sql Calculation Where Date Is Equal

**
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;