how to get this year opening from last year closing with condition? - tsql

I have table of data as below needs to use t-sql to generate
Year | Id | Entitle | Use | Max
-----------------------------------
2016 | 0001 | 15 | 5 | 20
2017 | 0001 | 15 | 2 | 20
2018 | 0001 | 15 | 4 | 20
I need to get opening and closing for each year, this year opening will be last year (opening + Entitle - Use), but it cannot exceed Max, if exceed Max then "Max" will be the opening.
this is the result I expected
year | Id | Opening | Entitle | Use | Max | Closing
-----------------------------------------------------
2016 | 0001 | 0 | 15 | 5 | 20 | 10
2017 | 0001 | 10 | 15 | 2 | 20 | 23
2018 | 0001 | 20 | 15 | 4 | 20 | 31

Here's another option, a recursive CTE will get you there.
DECLARE #TestData TABLE
(
[Year] INT
, [Id] NVARCHAR(10)
, [Entitle] INT
, [Use] INT
, [Max] INT
);
INSERT INTO #TestData (
[Year]
, [Id]
, [Entitle]
, [Use]
, [Max]
)
VALUES ( 2016, '0001', 15, 5, 20 )
, ( 2017, '0001', 15, 2, 20 )
, ( 2018, '0001', 15, 4, 20 );
INSERT INTO #TestData (
[Year]
, [Id]
, [Entitle]
, [Use]
, [Max]
)
VALUES ( 2015, '0002', 20, 7, 20 )
, ( 2016, '0002', 20, 7, 20 )
, ( 2017, '0002', 20, 4, 20 )
, ( 2018, '0002', 20, 13, 20 );
WITH [cte]
AS ( SELECT [a].[Year]
, [a].[Id]
, 0 AS [Opening]
, [a].[Entitle]
, [a].[Use]
, [a].[Entitle] - [a].[Use] AS [Closing]
FROM #TestData [a]
--Cross apply here to get our first record, earliest year for each Id for our anchor
CROSS APPLY (
SELECT [aa].[Id]
, MIN([aa].[Year]) AS [Year]
FROM #TestData [aa]
WHERE [aa].[Id] = [a].[Id]
GROUP BY [aa].[Id]
) [aaa]
WHERE [a].[Year] = [aaa].[Year]
AND [a].[Id] = [aaa].[Id]
UNION ALL
SELECT [c].[Year]
, [c].[Id]
, CASE WHEN [b].[Closing] > [c].[Max] THEN [c].[Max]
ELSE [b].[Closing]
END
, [c].[Entitle]
, [c].[Use]
, CASE WHEN [b].[Closing] > [c].[Max] THEN [c].[Max]
ELSE [b].[Closing]
END + [c].[Entitle] - [c].[Use] AS [Closing]
FROM [cte] [b]
INNER JOIN #TestData [c]
ON [c].[Id] = [b].[Id]
AND [c].[Year] = [b].[Year] + 1 )
SELECT *
FROM [cte]
ORDER BY [cte].[Id]
, [cte].[Year];

Simple SQL will not be enough here. You need to go trough each row and calculate the closing and opening values based on the previous year.
The idea would be to loop trough each row. Store the results. Add the results into a temp table.
I have made you the code here. Please note that I have used SSMS to implement it.
DECLARE #TempTable table (_ID varchar(255),Year int,Opening int, Entitle int,Used int,Max int, Closing int)
DECLARE #idColumn INT
DECLARE #ID varchar(255)
DECLARE #entitle INT
DECLARE #used INT
DECLARE #max INT
DECLARE #opening INT
DECLARE #closing INT
DECLARE #year INT
SELECT #idColumn = min( Id ) FROM MyTable
WHILE #idColumn is not null
BEGIN
SET #year = (SELECT Year FROM MyTable WHERE Id = #idColumn)
SET #ID = (SELECT [_ID] FROM MyTable WHERE Id = #idColumn)
IF #idColumn = 1
BEGIN
SET #entitle = (SELECT Entitle FROM MyTable WHERE Id = #idColumn);
SET #used = (SELECT Used FROM MyTable WHERE Id = #idColumn);
SET #opening = 0;
SET #closing = #opening + #entitle - #used;
SET #max = (SELECT Max FROM MyTable WHERE Id = #idColumn);
END
ELSE
BEGIN
SET #opening = #opening + #entitle - #used;
IF #opening > #max
BEGIN
SET #opening = #max;
END
SET #entitle = (SELECT Entitle FROM MyTable WHERE Id = #idColumn);
SET #used = (SELECT Used FROM MyTable WHERE Id = #idColumn);
SET #max = (SELECT Max FROM MyTable WHERE Id = #idColumn);
SET #closing = #opening + #entitle - #used;
END
INSERT INTO #TempTable (_ID , Year , Opening , Entitle , Used ,Max , Closing )
VALUES (#ID, #year, #opening, #entitle, #used, #max, #closing);
SELECT #idColumn = min( Id ) FROM MyTable WHERE Id > #idColumn
END
SELECT * FROM #TempTable

Related

Get Data Week Wise in SQL Server

I have a Table with columns ProductId, DateofPurchase, Quantity.
I want a report in which week it belongs to.
Suppose if I give March Month I can get the quantity for the march month.
But I want as below if I give date as parameter.
Here Quantity available for March month on 23/03/2018 is 100
Material Code Week1 Week2 Week3 Week4
12475 - - - 100
The logic is 1-7 first week, 8-15 second week, 16-23 third week, 24-30 fourth week
#Sasi, this can get you started. YOu will need to use CTE to build a template table that describes what happens yearly. Then using your table with inner join you can link it up and do a pivot to group the weeks.
Let me know if you need any tweaking.
DECLARE #StartDate DATE='20180101'
DECLARE #EndDate DATE='20180901'
DECLARE #Dates TABLE(
Workdate DATE Primary Key
)
DECLARE #tbl TABLE(ProductId INT, DateofPurchase DATE, Quantity INT);
INSERT INTO #tbl
SELECT 12475, '20180623', 100
;WITH Dates AS(
SELECT Workdate=#StartDate,WorkMonth=DATENAME(MONTH,#StartDate),WorkYear=YEAR(#StartDate), WorkWeek=datename(wk, #StartDate )
UNION ALL
SELECT CurrDate=DateAdd(WEEK,1,Workdate),WorkMonth=DATENAME(MONTH,DateAdd(WEEK,1,Workdate)),YEAR(DateAdd(WEEK,1,Workdate)),datename(wk, DateAdd(WEEK,1,Workdate)) FROM Dates D WHERE Workdate<#EndDate ---AND (DATENAME(MONTH,D.Workdate))=(DATENAME(MONTH,D.Workdate))
)
SELECT *
FROM
(
SELECT
sal.ProductId,
GroupWeek='Week'+
CASE
WHEN WorkWeek BETWEEN 1 AND 7 THEN '1'
WHEN WorkWeek BETWEEN 8 AND 15 THEN '2'
WHEN WorkWeek BETWEEN 16 AND 23 THEN '3'
WHEN WorkWeek BETWEEN 24 AND 30 THEN '4'
WHEN WorkWeek BETWEEN 31 AND 37 THEN '5'
WHEN WorkWeek BETWEEN 38 AND 42 THEN '6'
END,
Quantity
FROM
Dates D
JOIN #tbl sal on
sal.DateofPurchase between D.Workdate and DateAdd(DAY,6,Workdate)
)T
PIVOT
(
SUM(Quantity) FOR GroupWeek IN (Week1, Week2, Week3, Week4, Week5, Week6, Week7, Week8, Week9, Week10, Week11, Week12, Week13, Week14, Week15, Week16, Week17, Week18, Week19, Week20, Week21, Week22, Week23, Week24, Week25, Week26, Week27, Week28, Week29, Week30, Week31, Week32, Week33, Week34, Week35, Week36, Week37, Week38, Week39, Week40, Week41, Week42, Week43, Week44, Week45, Week46, Week47, Week48, Week49, Week50, Week51, Week52
/*add as many as you need*/)
)p
--ORDER BY
--1
option (maxrecursion 0)
Sample Data :
DECLARE #Products TABLE(Id INT PRIMARY KEY,
ProductName NVARCHAR(50))
DECLARE #Orders TABLE(ProductId INT,
DateofPurchase DATETIME,
Quantity BIGINT)
INSERT INTO #Products(Id,ProductName)
VALUES(1,N'Product1'),
(2,N'Product2')
INSERT INTO #Orders( ProductId ,DateofPurchase ,Quantity)
VALUES (1,'2018-01-01',130),
(1,'2018-01-09',140),
(1,'2018-01-16',150),
(1,'2018-01-24',160),
(2,'2018-01-01',30),
(2,'2018-01-09',40),
(2,'2018-01-16',50),
(2,'2018-01-24',60)
Query :
SELECT P.Id,
P.ProductName,
Orders.MonthName,
Orders.Week1,
Orders.Week2,
Orders.Week3,
Orders.Week4
FROM #Products AS P
INNER JOIN (SELECT O.ProductId,
SUM((CASE WHEN DATEPART(DAY,O.DateofPurchase) BETWEEN 1 AND 7 THEN O.Quantity ELSE 0 END)) AS Week1,
SUM((CASE WHEN DATEPART(DAY,O.DateofPurchase) BETWEEN 8 AND 15 THEN O.Quantity ELSE 0 END)) AS Week2,
SUM((CASE WHEN DATEPART(DAY,O.DateofPurchase) BETWEEN 16 AND 23 THEN O.Quantity ELSE 0 END)) AS Week3,
SUM((CASE WHEN DATEPART(DAY,O.DateofPurchase) >= 24 THEN O.Quantity ELSE 0 END)) AS Week4,
DATENAME(MONTH,O.DateofPurchase) AS MonthName
FROM #Orders AS O
GROUP BY O.ProductId,DATENAME(MONTH,O.DateofPurchase)) AS Orders ON P.Id = Orders.ProductId
Result :
-----------------------------------------------------------------------
| Id | ProductName | MonthNumber | Week1 | Week2 | Week3 | Week4 |
-----------------------------------------------------------------------
| 1 | Product1 | January | 130 | 140 | 150 | 160 |
| 2 | Product2 | January | 30 | 40 | 50 | 60 |
-----------------------------------------------------------------------

Improve performance on CTE with sub-queries

I have a table with this structure:
WorkerID Value GroupID Sequence Validity
1 '20%' 1 1 2018-01-01
1 '10%' 1 1 2017-06-01
1 'Yes' 1 2 2017-06-01
1 '2018-01-01' 2 1 2017-06-01
1 '17.2' 2 2 2017-06-01
2 '10%' 1 1 2017-06-01
2 'No' 1 2 2017-06-01
2 '2016-03-01' 2 1 2017-06-01
2 '15.9' 2 2 2017-06-01
This structure was created so that the client can create customized data for a worker. For example Group 1 can be something like "Salary" and Sequence is one value that belongs to that Group like "Overtime Compensation". The column Value is a VARCHAR(150) field and the correct validation and conversation is done in another part of the application.
The Validity column exist mainly for historical reasons.
Now I would like to show, for the different workers, the information in a grid where each row should be one worker (displaying the one with the most recent Validity):
Worker 1_1 1_2 2_1 2_2
1 20% Yes 2018-01-01 17.2
2 10% No 2016-03-01 15.9
To accomplish this I created a CTE that looks like this:
WITH CTE_worker_grid
AS
(
SELECT
worker,
/* 1 */
(
SELECT top 1 w.Value
FROM worker_values AS w
WHERE w.GroupID = 1
AND w.Sequence = 1
ORDER BY w.Validity DESC
) AS 1_1,
(
SELECT top 1 w.Value
FROM worker_values AS w
WHERE w.GroupID = 1
AND w.Sequence = 2
ORDER BY w.Validity DESC
) AS 1_2,
/* 2 */
(
SELECT top 1 w.Value
FROM worker_values AS w
WHERE w.GroupID = 2
AND w.Sequence = 1
ORDER BY w.Validity DESC
) AS 2_1,
(
SELECT top 1 w.Value
FROM worker_values AS w
WHERE w.GroupID = 2
AND w.Sequence = 2
ORDER BY w.Validity DESC
) AS 2_2
)
GO
This produces the correct result but it's very slow as it creates this grid for over 18'000 worker with almost 30 Groups and up to 20 Sequences in each Group.
How could one speed up the process of a CTE of this magnitude? Should CTE even be used? Can the sub-queries be changed or re-factored out to speed up the execution?
Use a PIVOT!
+----------+---------+---------+------------+---------+
| WorkerId | 001_001 | 001_002 | 002_001 | 002_002 |
+----------+---------+---------+------------+---------+
| 1 | 20% | Yes | 2018-01-01 | 17.2 |
| 2 | 10% | No | 2016-03-01 | 15.9 |
+----------+---------+---------+------------+---------+
SQL Fiddle: http://sqlfiddle.com/#!18/6e768/1
CREATE TABLE WorkerAttributes
(
WorkerID INT NOT NULL
, [Value] VARCHAR(50) NOT NULL
, GroupID INT NOT NULL
, [Sequence] INT NOT NULL
, Validity DATE NOT NULL
)
INSERT INTO WorkerAttributes
(WorkerID, Value, GroupID, Sequence, Validity)
VALUES
(1, '20%', 1, 1, '2018-01-01')
, (1, '10%', 1, 1, '2017-06-01')
, (1, 'Yes', 1, 2, '2017-06-01')
, (1, '2018-01-01', 2, 1, '2017-06-01')
, (1, '17.2', 2, 2, '2017-06-01')
, (2, '10%', 1, 1, '2017-06-01')
, (2, 'No', 1, 2, '2017-06-01')
, (2, '2016-03-01', 2, 1, '2017-06-01')
, (2, '15.9', 2, 2, '2017-06-01')
;WITH CTE_WA_RANK
AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY WorkerID, GroupID, [Sequence] ORDER BY Validity DESC) AS VersionNumber
, WA.WorkerID
, WA.GroupID
, WA.[Sequence]
, WA.[Value]
FROM
WorkerAttributes AS WA
),
CTE_WA
AS
(
SELECT
WA_RANK.WorkerID
, RIGHT('000' + CAST(WA_RANK.GroupID AS VARCHAR(3)), 3)
+ '_'
+ RIGHT('000' + CAST(WA_RANK.[Sequence] AS VARCHAR(3)), 3) AS SMART_KEY
, WA_RANK.[Value]
FROM
CTE_WA_RANK AS WA_RANK
WHERE
WA_RANK.VersionNumber = 1
)
SELECT
WorkerId
, [001_001] AS [001_001]
, [001_002] AS [001_002]
, [002_001] AS [002_001]
, [002_002] AS [002_002]
FROM
(
SELECT
CTE_WA.WorkerId
, CTE_WA.SMART_KEY
, CTE_WA.[Value]
FROM
CTE_WA
) AS WA
PIVOT
(
MAX([Value])
FOR
SMART_KEY IN
(
[001_001]
, [001_002]
, [002_001]
, [002_002]
)
) AS PVT

Generate Multiple rows from single row depending on date difference

I want to generate multiple rows from 1 rows depending on dates difference in dtStart and dtEnd
-- This is demo table to show the issue
create table #temp(Id int,hTenant int , dtStart datetime,dtEnd datetime)
Insert into #temp values(1,8,'2013-01-08 00:00:00.000','2014-01-01 00:00:00.000')
And data should be returned by query as :-
**Id** **Tenant** **Month** **Year**
1 8 Aug 2013
1 8 Sep 2013
1 8 Oct 2013
1 8 Nov 2013
1 8 Dec 2013
1 8 Jan 2014
How i can achieve this
I have created one table valued function which returns month and year but not able to join it with the table to fetch id and tenant
Create FUNCTION vw_emg_common_GetYearMonthDiffList ( #startdt datetime,#enddt datetime )
RETURNS #Months TABLE
(
Months int,
Years int,
StartDate datetime,
EndDate datetime
)
AS
BEGIN
WHILE (#startdt< #enddt)
BEGIN
INSERT INTO #Months(Months,Years,StartDate,EndDate) VALUES (MONTH(#startdt),Year(#startdt),#startdt,#enddt)
SET #startdt = DATEADD(MONTH,1,#startdt)
end
INSERT #Months
Select Months,Years,StartDate,EndDate from #Months
RETURN
end
Function call :-
select * FROM vw_emg_common_GetYearMonthDiffList('2013-01-01 00:00:00.000','2013-12-01 00:00:00.000' )
Try this method using Cross Join and CTE. You may need to create a function (or slightly modify). Fiddle demo is here
DECLARE #sd DATE = '20130801', #ed DATE = '20140101',
#id INT = 1, #hTenant INT = 8
;WITH CTE AS
(
SELECT DATEDIFF(MONTH, #sd, #ed) Months
)
SELECT DISTINCT #id Id, #hTenant Tenant,
DATENAME(MONTH, DATEADD(MONTH, number, #sd)) [Month],
YEAR(DATEADD(MONTH, number, #sd)) [Year]
FROM master..spt_values x
CROSS JOIN CTE
WHERE x.number BETWEEN 0 AND Months
Results
| ID | TENANT | MONTH | YEAR |
|----|--------|-----------|------|
| 1 | 8 | August | 2013 |
| 1 | 8 | September | 2013 |
| 1 | 8 | October | 2013 |
| 1 | 8 | November | 2013 |
| 1 | 8 | December | 2013 |
| 1 | 8 | January | 2014 |
Hope this helps you.
DECLARE #TEMP TABLE(ID INT,TENANT INT , DTSTART DATETIME,DTEND DATETIME)
INSERT INTO #TEMP VALUES(1,8,'2013-01-08 00:00:00.000','2014-01-01 00:00:00.000')
--You can create a function with the given logic
--It receives STARTDATE and ENDDATE
DECLARE #STARTDATE DATETIME = (SELECT DTSTART FROM #TEMP),
#ENDDATE DATETIME = (SELECT DTEND FROM #TEMP)
DECLARE #S INT = CAST(#STARTDATE AS INT)
DECLARE #E INT = CAST(#ENDDATE AS INT)
DECLARE #TAB TABLE (ID INT, DT DATETIME)
WHILE #S <= #E
BEGIN
INSERT INTO #TAB VALUES (#S,CAST(#S AS DATETIME))
SET #S = #S + 1
END
SELECT TEMP.ID,TEMP.TENANT,[Mname] MONTH,[Y] YEAR FROM (
SELECT DATEPART(YEAR,DT) [Y],DATEPART(MONTH,DT) [Mnum],DATENAME(MONTH,DT) [Mname] FROM #TAB
GROUP BY DATEPART(YEAR,DT),DATEPART(MONTH,DT),DATENAME(MONTH,DT)) LU,#TEMP TEMP
ORDER BY [Y],[Mnum]
Result:

Joining query results into one

This is my table to track down the employees off days. This example is only for one person.
ID PID Year OffDays DayTypeNumber
------------------------------------------
1 1 2011 10 1
2 1 2011 5 2
3 1 2012 20 1
4 1 2012 3 2
I would like to write such a query that should only show one result for each year with additional column
Year OffDays(1) OffDays(2)
------------------------------------------
2011 10 5
2012 20 3
You can use the PIVOT function for this:
select year,
[1] [OffDays(1)],
[2] [OffDays(2)]
from
(
select year, offdays, daytypenumber
from yourtable
) src
pivot
(
sum(offdays)
for daytypenumber in([1], [2])
) piv
See SQL Fiddle with Demo
Result:
| YEAR | OFFDAYS(1) | OFFDAYS(2) |
----------------------------------
| 2011 | 10 | 5 |
| 2012 | 20 | 3 |
Or you can use an aggregate function with a CASE statement:
select year,
sum(case when daytypenumber = 1 then offdays end) [OffDays(1)],
sum(case when daytypenumber = 2 then offdays end) [OffDays(2)]
from yourtable
group by year
See SQL Fiddle with Demo
If you only have two types that you are comparing, then you can use subqueries:
select t1.year,
[OffDays(1)],
[OffDays(2)]
from
(
select sum(offdays) [OffDays(1)], year
from yourtable
where daytypenumber = 1
group by year
) t1
left join
(
select sum(offdays) [OffDays(2)], year
from yourtable
where daytypenumber = 2
group by year
) t2
on t1.year = t2.year
See SQL Fiddle with Demo
The above answers will work great, if you have a known number of values for DayTypeNumber, but if those are unknown then you can use dynamic SQL to generate the PIVOT:
DECLARE #cols AS NVARCHAR(MAX),
#colNames AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(DayTypeNumber)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colNames = STUFF((SELECT distinct ', ' + QUOTENAME(DayTypeNumber)
+' as [OffDays('+cast(DayTypeNumber as varchar(10))+')]'
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT year,' + #colNames + ' from
(
select year, offdays, daytypenumber
from yourtable
) x
pivot
(
sum(offdays)
for daytypenumber in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
All of these will produce the same results:
| YEAR | OFFDAYS(1) | OFFDAYS(2) |
----------------------------------
| 2011 | 10 | 5 |
| 2012 | 20 | 3 |

generate new column using other columns

I am stuck with generating a new column. The table has three columns(C_ID, C_rank, Date).
C_ID C_ Rank NewColumn(Cycle) Date
42 A 1 October 14, 2010
42 B 1 October 26, 2010
42 A 2 February 16, 2011
43 A 1 December 17, 2010
44 A 1 July 28, 2010
44 B 1 August 10, 2010
44 A 2 January 11, 2011
44 B 2 January 28, 2011
45 A 1 July 30, 2010
45 B 1 August 9, 2010
45 B 1 September 24, 2010
45 A 2 April 5, 2011
45 B 2 April 26, 2011
I want to generate one more column called Cycle in such a way that for each C_ID, it should generate the number start from one and increment the number from next C_rank = 'A' (a shown above).
I tried using row_number, but no luck.
Maybe some loop option till next C_Rank = 'A' works.
How can this be done?
You should be able to get this done using ROW_NUMBER() and PARTITION BY
;WITH YourDataCTE AS
(
SELECT
C_ID, C_Rank, Date,
ROW_NUMBER() OVER(PARTITION BY C_ID,C_Rank ORDER BY Date DESC) AS 'Cycle'
FROM
dbo.YourTable
)
SELECT *
FROM YourDataCTE
Does that do what you're looking for??
The PARTITION BY C_ID,C_Rank will cause the ROW_NUMBER to start at 1 again for each different value of C_ID,C_Rank - I didn't know what ORDER BY clause within a single partition (a single value of C_ID,C_Rank) you're looking for and just guessed it might be Date DESC (newest date first).
You could count the number of previous A's in a subquery:
select *
, (
select count(*)
from #YourTable yt2
where yt2.C_ID = yt1.C_ID
and yt2.C_Rank = 'A'
and yt2.Date <= yt1.Date
) as Cycle
from #YourTable yt1
order by
C_ID, Date
Example at ODATA.
Do a self join for all records with the same C_ID, a previous date, and a C_Rank='A' and count them.
select t1.C_ID, t1.C_Rank, count(t2.C_Rank) Cycle, t1.Date
from MyTable t1
left join MyTable t2 on t1.C_ID=t2.C_ID
and t2.Date<=t1.Date
and t2.C_Rank='A'
group by t1.C_ID, t1.C_Rank, t1.Date
order by t1.C_ID, t1.Date
Below code fulfill the requirement:
create table #Temp_Table
(
C_ID int
, C_Rank char(1)
, Date datetime
, NewColumn int
)
insert into #Temp_Table
(
C_ID
, C_Rank
, Date
)
select 42, ‘A’, ’10/14/2010′
union all
select 42, ‘B’, ’10/26/2010′
union all
select 42, ‘B’, ’10/14/2010′
union all
select 42, ‘C’, ’10/26/2010′
union all
select 42, ‘A’,’02/16/2011′
union all
select 43, ‘A’, ’12/17/2010′
union all
select 44, ‘A’, ’07/28/2010′
union all
select 44, ‘B’, ’08/10/2010′
union all
select 44, ‘A’, ’01/11/2011′
union all
select 44, ‘B’, ’01/28/2011′
union all
select 44, ‘C’, ’10/14/2010′
union all
select 44, ‘D’, ’10/26/2010′
Select ‘Original Data’ Comment
,*
from #Temp_Table
/*
This would be Actual Script to get the New ID based on information you provided
*/
Declare #Count int
,#C_ID int
,#C_Rank char(1)
,#total_Count int
,#Count_Partition int
,#Previous_ID int
Declare #Table Table (ID int IDENTITY(1,1), C_ID int, C_Rank char(1), Date datetime, NewColumn int )
Set #Count = 1
Set #Count_Partition = 0
insert into #Table
Select *
from #Temp_Table
Select #total_Count = ISNULL(MAX(ID),0)
from #Table
While #Count < = #total_Count
Begin
Select #C_ID = C_ID
,#C_Rank = C_Rank
From #Table
Where ID = #Count
If #Count = 1
Set #Previous_ID = #C_ID
If #Previous_ID != #C_ID
Set #Count_Partition = 1
Else If #C_Rank = 'A'
Set #Count_Partition = #Count_Partition + 1
update #Table
Set NewColumn = #Count_Partition
Where ID = #Count
Set #Previous_ID = #C_ID
Set #Count = #Count + 1
End
Select C_ID
, C_Rank
, [Date]
, NewColumn
from #Table
–Drop table #Temp_Table