| Author |
Topic |
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-01 : 20:28:37
|
| Hi There,I have two tables, here is sample:TableA (SID, Cat, DueDate and SalesAmount)SID Cat Due_Date Amount577 001 2007-04-01 00:00:00.000 563500.00577 001 2007-05-01 00:00:00.000 714380.71577 001 2008-06-01 00:00:00.000 269876.68577 001 2008-08-01 00:00:00.000 407688.99Table B (SID, Cat, RateStartDate, Rate)SID Cat RateStartDate Rate577 001 2007-04-01 00:00:00.000 0.00300577 001 2008-03-01 00:00:00.000 0.00400I would like to populate Rate to Table A based on Due_Date in Table A and RateStartDate in Table B, if Due_Date is between current RateStartDate and next RateStartDate, then rate with current RateStartDate will be used. SID and Cat are the keys to join table A and B.So the result Table C I would like to have:SID Cat Due_Date Amount Rate577 001 2007-04-01 00:00:00.000 563500.00 0.00300577 001 2007-05-01 00:00:00.000 714380.71 0.00300577 001 2008-06-01 00:00:00.000 269876.68 0.00400577 001 2008-08-01 00:00:00.000 407688.99 0.00400Thanks a lot |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-01 : 21:07:40
|
If you are on SQL 2005 or higher, you can do it using cross apply as follows:update a set rate = b.ratefrom TableA a cross apply ( select top 1 rate from TableB b where b.ratestartdate <= a.duedate and b.sid = a.sid and b.cat = a.cat order by ratestartdate desc )b |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-01 : 21:27:51
|
| Sunita,Thank you so much for your quick reply!It works perfectly, but I still have to learn the logic you write here, this is new to me.Thanks again |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-02 : 09:13:58
|
| You are quite welcome, and glad it worked out for you!The logic is fairly simple. If you run the query after you replce the first two lines ( "update a set rate = b.rate" ) with a " SELECT * " you can see what the rest of the query is doing. The cross apply operator tells SQL something like this:1. Take EACH row in the left table (TableA).2. Evaluate what is to the right of the cross apply operator for that SPECIFIC ROW that you picked in step 1.3. Put (1) and (2) together as the result of the query.4. The part to the right of the cross apply operator is a simple select. In the where condition, a.duedate, a.sid and a.cat refer to the one specific row picked in step 1. Ordering by the ratestartdate date in descending order and picking the top 1 row makes sure that we get the rate for the latest ratestartdate that satisfied the where conditions.There are other ways to do it, and some of them may even be more efficient (which would be a big consideration if you have millions of rows that you are trying to update). But I like the simplicity of the cross apply. |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-15 : 13:59:28
|
| Sunita,I think I mis-state my problem here. Sorry about that, here is the sample data I got:TableA (SID, DueDate and SalesAmount)SID Due_Date Amount577 2010-11-01 00:00:00.000 563500.00Table B (SID, RateStartDate, Rate)SID RateStartDate Rate577 20010-03-01 00:00:00.000 0.00100577 20010-10-01 00:00:00.000 0.00200577 20011-01-01 00:00:00.000 0.00300577 20011-03-01 00:00:00.000 0.00400I would like to populate Rate to Table A based on Due_Date in Table A and RateStartDate in Table B, if Due_Date is between current RateStartDate and next RateStartDate, then rate with current RateStartDate will be used, also Table C will have all month up to current month minus 1 with Rate in Table B respectively. SID is the key to join table A and B.So the result Table C I would like to have:SID Due_Date Amount Rate577 2010-11-01 00:00:00.000 563500.00 0.00200577 2010-12-01 00:00:00.000 714380.71 0.00200577 2011-01-01 00:00:00.000 269876.68 0.00300577 2011-02-01 00:00:00.000 407688.99 0.00300577 2011-03-01 00:00:00.000 407688.99 0.00400Essentially this is the first part to figure out the rate, then the next part is to calculate ending balance (Rate*Amount) as ending balance, then ending balance bacomes Amount for next Due_Date. I think I need to put the solution you had for this together like this:SID Due_Date Amount Rate EndingBalance 577 2010-11-01 00:00:00.000 563500.00 0.00200 563500*0.02577 2010-12-01 00:00:00.000 563500*0.02 0.00200 563500*0.02*0.02577 2011-01-01 00:00:00.000 563500*0.02*0.02 0.00300 563500*0.02*0.02*0.03...Thanks |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-15 : 19:38:04
|
Hi there dz0001!Here is my first attempt to do what you described. (Usually I get it right only on the third attempt). It looks long, but the logic and code is fairly simple.-- THIS PART IS CREATING MY TEST TABLES AND DATACREATE TABLE TA(SID INT, DueDate DATETIME, Amount DECIMAL(19,2));CREATE TABLE TB(SID INT, RateStartDate DATETIME, Rate DECIMAL(9,5));INSERT INTO TA VALUES (577,'20101101',563500);INSERT INTO TA VALUES (578,'20090101',563500);INSERT INTO TB VALUES (577,'20100301',0.001);INSERT INTO TB VALUES (577,'20101001',0.002);INSERT INTO TB VALUES (577,'20110101',0.003);INSERT INTO TB VALUES (577,'20110301',0.004);INSERT INTO TB VALUES (578,'20090101',0.004);INSERT INTO TB VALUES (578,'20090901',0.003);INSERT INTO TB VALUES (578,'20100901',0.005);-- PART 1-- CONSTRUCTING A RATE TABLE THAT HAS RATES FOR ALL MONTHS.CREATE TABLE #TC( SID INT NOT NULL, DueDate DATETIME NOT NULL, Amount DECIMAL(19,2) NULL, Rate DECIMAL(9,5) NOT NULL PRIMARY KEY CLUSTERED (SID, DueDate));WITH CalendarCTE AS ( SELECT SID, DueDate, Amount FROM TA UNION ALL SELECT c.SID,DATEADD(mm,1,c.DueDate), null FROM CalendarCTE c WHERE DATEADD(mm,2,c.DueDate) < GETDATE())INSERT INTO #TCSELECT c.SID, c.DueDate, Amount, b.RateFROM CalendarCTE c CROSS APPLY ( SELECT TOP 1 Rate FROM TB b WHERE b.RateStartDate <= c.DueDate AND c.SID = b.[SID] ORDER BY b.RateStartDate DESC ) b;-- PART 2-- CUMULATIVE AMOUNTS-- See the two ??? below. I calculated the balances differently than you-- described. May be that needs to be changed?WITH CTE AS( SELECT *, cast(Amount*Rate as decimal(19,5)) AS Interest -- ???? FROM #TC WHERE Amount IS NOT NULL UNION ALL SELECT t.SID, t.DueDate, cast(c.Amount+c.Interest AS DECIMAL(19,2)), t.Rate, CAST((c.Amount+c.Interest)*t.Rate AS DECIMAL(19,5)) -- ??? FROM #TC t INNER JOIN CTE c ON t.DueDate = DATEADD(mm,1,c.DueDate) AND t.SID = c.SID)SELECT * FROM CTE ORDER BY SID, Duedate;-- CLEANUP DROP TABLE #TC; |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-16 : 11:06:17
|
| Sunita,You are right, I miss column in my calculation, here is updated tables and columns involved in calculation:-- THIS PART IS CREATING MY TEST TABLES AND DATACREATE TABLE TA(SID INT, DueDate DATETIME, Amount DECIMAL(19,2));CREATE TABLE TB(SID INT, RateStartDate DATETIME, Rate DECIMAL(9,5));CREATE TABLE TC(SID INT, ChargestartDate DATETIME, Charge DECIMAL(9,5));INSERT INTO TA VALUES (577,'20101101',563500);INSERT INTO TA VALUES (578,'20090101',563500);INSERT INTO TB VALUES (577,'20100301',0.001);INSERT INTO TB VALUES (577,'20101001',0.002);INSERT INTO TB VALUES (577,'20110101',0.003);INSERT INTO TB VALUES (577,'20110301',0.004);INSERT INTO TB VALUES (578,'20090101',0.004);INSERT INTO TB VALUES (578,'20090901',0.003);INSERT INTO TB VALUES (578,'20100901',0.005);INSERT INTO TC VALUES (577,'20100301',200.00);INSERT INTO TC VALUES (577,'20101001',300.00);INSERT INTO TC VALUES (577,'20110101',400.00);INSERT INTO TC VALUES (577,'20110301',500.00);INSERT INTO TC VALUES (578,'20090101',600.00);INSERT INTO TC VALUES (578,'20090901',700.00);INSERT INTO TC VALUES (578,'20100901',800.00);FinalTable:SID DueDate Amount Rate Charge ScheduleRate ScheduleCharge EndingBalanceScheduleRate = Amount*RateScheduleCharge = Charge - ScheduleRateEndingBalance = Amount - ScheduleChargePrevious EndingBalance becomes Amount for next periodNotice I add Charge table apart from Rate table, this should be proper calculation.Thanks again |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-16 : 21:35:18
|
This makes more sense to me too! I made minor changes to the code. If the results do not look right, I might have messed up the formulas (shown in red).-- PART 1-- CONSTRUCTING A RATE TABLE THAT HAS RATES FOR ALL MONTHS.CREATE TABLE #TC( SID INT NOT NULL, DueDate DATETIME NOT NULL, Amount DECIMAL(19,2) NULL, Rate DECIMAL(9,5) NOT NULL, Charge DECIMAL(9,5) NOT NULL, PRIMARY KEY CLUSTERED (SID, DueDate));WITH CalendarCTE AS ( SELECT SID, DueDate, Amount FROM TA UNION ALL SELECT c.SID,DATEADD(mm,1,c.DueDate), null FROM CalendarCTE c WHERE DATEADD(mm,2,c.DueDate) < GETDATE())INSERT INTO #TCSELECT c.SID, c.DueDate, Amount, b.Rate, t.ChargeFROM CalendarCTE c CROSS APPLY ( SELECT TOP 1 Rate FROM TB b WHERE b.RateStartDate <= c.DueDate AND c.SID = b.[SID] ORDER BY b.RateStartDate DESC ) b CROSS APPLY ( SELECT TOP 1 Charge FROM TC t WHERE t.ChargestartDate <= c.DueDate AND c.SID = t.[SID] ORDER BY t.ChargestartDate DESC )t;-- PART 2-- CUMULATIVE AMOUNTS-- See the two ??? below. I calculated the balances differently than you-- described. May be that needs to be changed?WITH CTE AS( SELECT *, cast(Amount*Rate as decimal(19,5)) AS ScheduleRate, cast(Charge-Amount*Rate as decimal(19,5)) AS ScheduleCharge, CAST(Amount - (Charge-Amount*Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC WHERE Amount IS NOT NULL UNION ALL SELECT t.SID, t.DueDate, cast(c.EndingBalance AS DECIMAL(19,2)), t.Rate, t.Charge, cast(c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleRate, CAST(t.Charge-c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleCharge, CAST(c.EndingBalance-(t.Charge-c.EndingBalance*t.Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC t INNER JOIN CTE c ON t.DueDate = DATEADD(mm,1,c.DueDate) AND t.SID = c.SID)SELECT * FROM CTE ORDER BY SID, Duedate;-- CLEANUP DROP TABLE #TC; |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-17 : 22:16:51
|
| Hi Sunita,I try to add another lookup look TD to cross apply by myself, however I got the error, could you point it out what I did wrong?-- THIS PART IS CREATING MY TEST TABLES AND DATACREATE TABLE TA(SID INT, CATID int, CAT int, DueDate DATETIME, Amount DECIMAL(19,2));CREATE TABLE TB(SID INT, RateStartDate DATETIME, Rate DECIMAL(9,5));CREATE TABLE TC(SID INT, ChargestartDate DATETIME, Charge DECIMAL(9,5));CREATE TABLE TD(CATID int, CAT INT, CatStartDate DATETIME, CatRate DECIMAL(9,5));INSERT INTO TA VALUES (577, 411, 001, '20101101',563500);INSERT INTO TA VALUES (578, 412, 002, '20090101',563500);INSERT INTO TB VALUES (577,'20100301',0.001);INSERT INTO TB VALUES (577,'20101001',0.002);INSERT INTO TB VALUES (577,'20110101',0.003);INSERT INTO TB VALUES (577,'20110301',0.004);INSERT INTO TB VALUES (578,'20090101',0.004);INSERT INTO TB VALUES (578,'20090901',0.003);INSERT INTO TB VALUES (578,'20100901',0.005);INSERT INTO TC VALUES (577,'20100301',200.00);INSERT INTO TC VALUES (577,'20101001',300.00);INSERT INTO TC VALUES (577,'20110101',400.00);INSERT INTO TC VALUES (577,'20110301',500.00);INSERT INTO TC VALUES (578,'20090101',600.00);INSERT INTO TC VALUES (578,'20090901',700.00);INSERT INTO TC VALUES (578,'20100901',800.00);INSERT INTO TD VALUES (411,001,'20090701',0.06);INSERT INTO TD VALUES (411,002,'20101001',0.08);INSERT INTO TD VALUES (412,002,'20090401',0.09);INSERT INTO TD VALUES (412,002,'20100901',0.04);-- PART 1-- CONSTRUCTING A RATE TABLE THAT HAS RATES FOR ALL MONTHS.CREATE TABLE #TC( SID INT NOT NULL, CATID INT NOT NULL, CAT INT NOT NULL, DueDate DATETIME NOT NULL, Amount DECIMAL(19,2) NULL, Rate DECIMAL(9,5) NOT NULL, CatRate DECIMAL(9,5) NOT NULL, Charge DECIMAL(9,5) NOT NULL, PRIMARY KEY CLUSTERED (SID, DueDate));WITH CalendarCTE AS ( SELECT SID, CATID, CAT,DueDate, Amount FROM TA UNION ALL SELECT c.SID,DATEADD(mm,1,c.DueDate), null FROM CalendarCTE c WHERE DATEADD(mm,2,c.DueDate) < GETDATE())INSERT INTO #TCSELECT c.SID, c.CATID, c.CAT, c.DueDate, Amount, b.Rate, td.CatRate, t.ChargeFROM CalendarCTE c CROSS APPLY ( SELECT TOP 1 Rate FROM TB b WHERE b.RateStartDate <= c.DueDate AND c.SID = b.[SID] ORDER BY b.RateStartDate DESC ) b CROSS APPLY ( SELECT TOP 1 CatRate FROM TD td WHERE td.CatStartDate <= c.DueDate AND c.CATID = td.[CATID] AND c.CAT = td.[CAT] ORDER BY td.CatStartDate DESC )td CROSS APPLY ( SELECT TOP 1 Charge FROM TC t WHERE t.ChargestartDate <= c.DueDate AND c.SID = t.[SID] ORDER BY t.ChargestartDate DESC )t;-- PART 2-- CUMULATIVE AMOUNTS-- See the two ??? below. I calculated the balances differently than you-- described. May be that needs to be changed?WITH CTE AS( SELECT *, cast(Amount*Rate as decimal(19,5)) AS ScheduleRate, cast(Charge-Amount*Rate as decimal(19,5)) AS ScheduleCharge, CAST(Amount - (Charge-Amount*Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC WHERE Amount IS NOT NULL UNION ALL SELECT t.SID, t.CATID, t.CAT, t.DueDate, cast(c.EndingBalance AS DECIMAL(19,2)), t.Rate, td.CatRate, t.Charge, cast(c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleRate, CAST(t.Charge-c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleCharge, CAST(c.EndingBalance-(t.Charge-c.EndingBalance*t.Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC t INNER JOIN CTE c ON t.DueDate = DATEADD(mm,1,c.DueDate) AND t.SID = c.SID)SELECT * FROM CTE ORDER BY SID, Duedate;-- CLEANUP DROP TABLE #TC; |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-18 : 07:22:08
|
| How does CATID relate to SID? In all other tables, the there is a SID column - which we can use to relate the data to each other in those tables.If the new table TD is not specific to a SID, can you describe the business rules that should be used to associate rows from that table (CATID, CAT etc.) to a specific SID or SID+Date combintation? |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 09:30:06
|
| CATID and CAT are ResellerID and ResellerCategoryID. For each salesID in TA, there is resellerID (CATID) and reseller categoryID (CAT) associated with it. Each reseller has different discountRate based on CATID and CAT, and they can be adjusted periodically. Business wants to have CatRate assigned based on table TD, the rule is the same as Charge and IntRate, it is based on DueDate in TA, and CatRateStartDate in TD, plus join between CATID and CAT between TA and TD. I need to populate right CatRate to corresponding SID. I thought I can use Cross Apply you show me to add this table TD and assign value to it since the logic is almost the same, I got error:"All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.", Many thanks |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 14:28:25
|
| I make some changes on the code, there is no error, but return data set is not what I expect:-- THIS PART IS CREATING MY TEST TABLES AND DATACREATE TABLE TA(SID INT, CATID int, CAT int, DueDate DATETIME, Amount DECIMAL(19,2));CREATE TABLE TB(SID INT, RateStartDate DATETIME, Rate DECIMAL(9,5));CREATE TABLE TC(SID INT, ChargestartDate DATETIME, Charge DECIMAL(9,5));CREATE TABLE TD(CATID int, CAT INT, CatStartDate DATETIME, CatRate DECIMAL(9,5));INSERT INTO TA VALUES (577, 411, 001, '20101101',563500);INSERT INTO TA VALUES (578, 412, 002, '20090101',563500);INSERT INTO TB VALUES (577,'20100301',0.001);INSERT INTO TB VALUES (577,'20101001',0.002);INSERT INTO TB VALUES (577,'20110101',0.003);INSERT INTO TB VALUES (577,'20110301',0.004);INSERT INTO TB VALUES (578,'20090101',0.004);INSERT INTO TB VALUES (578,'20090901',0.003);INSERT INTO TB VALUES (578,'20100901',0.005);INSERT INTO TC VALUES (577,'20100301',200.00);INSERT INTO TC VALUES (577,'20101001',300.00);INSERT INTO TC VALUES (577,'20110101',400.00);INSERT INTO TC VALUES (577,'20110301',500.00);INSERT INTO TC VALUES (578,'20090101',600.00);INSERT INTO TC VALUES (578,'20090901',700.00);INSERT INTO TC VALUES (578,'20100901',800.00);INSERT INTO TD VALUES (411,001,'20090701',0.06);INSERT INTO TD VALUES (411,002,'20101001',0.08);INSERT INTO TD VALUES (412,002,'20090401',0.09);INSERT INTO TD VALUES (412,002,'20100901',0.04);CREATE TABLE #TC( SID INT NOT NULL, CATID INT NOT NULL, CAT INT NOT NULL, DueDate DATETIME NOT NULL, Amount DECIMAL(19,2) NULL, Rate DECIMAL(9,5) NOT NULL, CatRate DECIMAL(9,5) NOT NULL, Charge DECIMAL(9,5) NOT NULL, PRIMARY KEY CLUSTERED (SID, DueDate));WITH CalendarCTE AS ( SELECT SID, CATID, CAT,DueDate, Amount FROM TA UNION ALL SELECT c.SID,c.CATID, c.CAT,DATEADD(mm,1,c.DueDate), null FROM CalendarCTE c WHERE DATEADD(mm,2,c.DueDate) < GETDATE())INSERT INTO #TCSELECT c.SID, c.CATID, c.CAT, c.DueDate, Amount, b.Rate, td.CatRate, t.ChargeFROM CalendarCTE c CROSS APPLY ( SELECT TOP 1 Rate FROM TB b WHERE b.RateStartDate <= c.DueDate AND c.SID = b.[SID] ORDER BY b.RateStartDate DESC ) b CROSS APPLY ( SELECT TOP 1 CatRate FROM TD td WHERE td.CatStartDate <= c.DueDate AND c.CATID = td.[CATID] AND c.CAT = td.[CAT] ORDER BY td.CatStartDate DESC )td CROSS APPLY ( SELECT TOP 1 Charge FROM TC t WHERE t.ChargestartDate <= c.DueDate AND c.SID = t.[SID] ORDER BY t.ChargestartDate DESC )t;-- PART 2-- CUMULATIVE AMOUNTS-- See the two ??? below. I calculated the balances differently than you-- described. May be that needs to be changed?WITH CTE AS( SELECT *, cast(Amount*Rate as decimal(19,5)) AS ScheduleRate, cast(Charge-Amount*Rate as decimal(19,5)) AS ScheduleCharge, CAST(Amount - (Charge-Amount*Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC WHERE Amount IS NOT NULL UNION ALL SELECT t.SID, t.CATID, t.CAT, t.DueDate, cast(c.EndingBalance AS DECIMAL(19,2)), t.Rate, t.CatRate, t.Charge, cast(c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleRate, CAST(t.Charge-c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleCharge, CAST(c.EndingBalance-(t.Charge-c.EndingBalance*t.Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC t INNER JOIN CTE c ON t.DueDate = DATEADD(mm,1,c.DueDate) AND t.SID = c.SID)SELECT * FROM CTE ORDER BY SID, Duedate; |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-18 : 14:54:53
|
| I had missed that you had added two columns CAT and CATID in table TA. So everything you did up to the final select seems correct. But in the final select, how should the CatRate be taken into account? Currently the Charge, ScheduleRate, ScheduleCharge and EndingBalance are calculated without using the CatRate at all. Can you describe or post the formula you want to use to calculate these when you take into account the CatRate? |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 15:05:50
|
quote: Originally posted by sunitabeck I had missed that you had added two columns CAT and CATID in table TA. So everything you did up to the final select seems correct. But in the final select, how should the CatRate be taken into account? Currently the Charge, ScheduleRate, ScheduleCharge and EndingBalance are calculated without using the CatRate at all. Can you describe or post the formula you want to use to calculate these when you take into account the CatRate?
Sorry about that I did not explain clearly. Yes there is amount calculated by using CatRate. The calculation is:DisAmt (discount amount) = CatRate * Amount (from Ending Balance). |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-18 : 15:08:50
|
| Would that then reduce the Amount for the next month? What I am looking for is something like this that you had posted earlier:ScheduleRate = Amount*RateScheduleCharge = Charge - ScheduleRateEndingBalance = Amount - ScheduleChargePrevious EndingBalance becomes Amount for next periodWould DisAmt change any of the formulas above? |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 15:13:30
|
| Sunita,Here is my attempt, but only 5 rows get returned, I think something I did wrong here, could you run the sample and confirm that?-- THIS PART IS CREATING MY TEST TABLES AND DATACREATE TABLE TA(SID INT, CATID int, CAT int, DueDate DATETIME, Amount DECIMAL(19,2));CREATE TABLE TB(SID INT, RateStartDate DATETIME, Rate DECIMAL(9,5));CREATE TABLE TC(SID INT, ChargestartDate DATETIME, Charge DECIMAL(9,5));CREATE TABLE TD(CATID int, CAT INT, CatStartDate DATETIME, CatRate DECIMAL(9,5));INSERT INTO TA VALUES (577, 411, 001, '20101101',563500);INSERT INTO TA VALUES (578, 412, 002, '20090101',563500);INSERT INTO TB VALUES (577,'20100301',0.001);INSERT INTO TB VALUES (577,'20101001',0.002);INSERT INTO TB VALUES (577,'20110101',0.003);INSERT INTO TB VALUES (577,'20110301',0.004);INSERT INTO TB VALUES (578,'20090101',0.004);INSERT INTO TB VALUES (578,'20090901',0.003);INSERT INTO TB VALUES (578,'20100901',0.005);INSERT INTO TC VALUES (577,'20100301',200.00);INSERT INTO TC VALUES (577,'20101001',300.00);INSERT INTO TC VALUES (577,'20110101',400.00);INSERT INTO TC VALUES (577,'20110301',500.00);INSERT INTO TC VALUES (578,'20090101',600.00);INSERT INTO TC VALUES (578,'20090901',700.00);INSERT INTO TC VALUES (578,'20100901',800.00);INSERT INTO TD VALUES (411,001,'20090701',0.06);INSERT INTO TD VALUES (411,002,'20101001',0.08);INSERT INTO TD VALUES (412,002,'20090401',0.09);INSERT INTO TD VALUES (412,002,'20100901',0.04);-- PART 1-- CONSTRUCTING A RATE TABLE THAT HAS RATES FOR ALL MONTHS.CREATE TABLE #TC( SID INT NOT NULL, CATID INT NOT NULL, CAT INT NOT NULL, DueDate DATETIME NOT NULL, Amount DECIMAL(19,2) NULL, Rate DECIMAL(9,5) NOT NULL, CatRate DECIMAL(9,5) NOT NULL, Charge DECIMAL(9,5) NOT NULL, PRIMARY KEY CLUSTERED (SID, DueDate));WITH CalendarCTE AS ( SELECT SID, CATID, CAT,DueDate, Amount FROM TA UNION ALL SELECT c.SID,c.CATID, c.CAT,DATEADD(mm,1,c.DueDate), null FROM CalendarCTE c WHERE DATEADD(mm,2,c.DueDate) < GETDATE())INSERT INTO #TCSELECT c.SID, c.CATID, c.CAT, c.DueDate, Amount, b.Rate, td.CatRate, t.ChargeFROM CalendarCTE c CROSS APPLY ( SELECT TOP 1 Rate FROM TB b WHERE b.RateStartDate <= c.DueDate AND c.SID = b.[SID] ORDER BY b.RateStartDate DESC ) b CROSS APPLY ( SELECT TOP 1 CatRate FROM TD td WHERE td.CatStartDate <= c.DueDate AND c.CATID = td.[CATID] AND c.CAT = td.[CAT] ORDER BY td.CatStartDate DESC )td CROSS APPLY ( SELECT TOP 1 Charge FROM TC t WHERE t.ChargestartDate <= c.DueDate AND c.SID = t.[SID] ORDER BY t.ChargestartDate DESC )t;-- PART 2-- CUMULATIVE AMOUNTS-- See the two ??? below. I calculated the balances differently than you-- described. May be that needs to be changed?WITH CTE AS( SELECT *, cast(Amount*Rate as decimal(19,5)) AS ScheduleRate, cast(Charge-Amount*Rate as decimal(19,5)) AS ScheduleCharge, cast(Amount*CatRate as decimal(19,5)) AS DisAmt, CAST(Amount - (Charge-Amount*Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC WHERE Amount IS NOT NULL UNION ALL SELECT t.SID, t.CATID, t.CAT, t.DueDate, cast(c.EndingBalance AS DECIMAL(19,2)), t.Rate, t.CatRate, t.Charge, cast(c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleRate, CAST(t.Charge-c.EndingBalance*t.Rate as decimal(19,5)) AS ScheduleCharge, CAST(c.EndingBalance*t.CatRate as decimal(19,5)) AS DisAmt, CAST(c.EndingBalance-(t.Charge-c.EndingBalance*t.Rate) AS DECIMAL(19,5)) AS EndingBalance FROM #TC t INNER JOIN CTE c ON t.DueDate = DATEADD(mm,1,c.DueDate) AND t.SID = c.SID)SELECT * FROM CTE ORDER BY SID, Duedate; |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 15:34:23
|
quote: Originally posted by sunitabeck Would that then reduce the Amount for the next month? What I am looking for is something like this that you had posted earlier:ScheduleRate = Amount*RateScheduleCharge = Charge - ScheduleRateEndingBalance = Amount - ScheduleChargePrevious EndingBalance becomes Amount for next periodWould DisAmt change any of the formulas above?
No DisAmt will not change any of the formulas above, Report only needs to know accurate DisAmt for each resellers at that date range, so CatRate*EndingBalance = DisAmt is all needed. But the code I mimic yours seems not correct since not all records get returned. |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-18 : 15:44:52
|
I made the following changes (after removing all rows from table TD).INSERT INTO TD VALUES (411,001,'20090701',0.06);INSERT INTO TD VALUES (411,001,'20101001',0.08);INSERT INTO TD VALUES (412,002,'20090101',0.09);INSERT INTO TD VALUES (412,002,'20100901',0.04); I don't know if those are the right things to do. The first change because I thought 577 is associated with 411 and 01 rather than 411 and 02.The second change because the dates for 578 start in 20090101, so the way the code is written, it expects to find a CatStartDate earlier than or equal to that date. |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-18 : 15:52:31
|
quote: Originally posted by sunitabeck I made the following changes (after removing all rows from table TD).INSERT INTO TD VALUES (411,001,'20090701',0.06);INSERT INTO TD VALUES (411,001,'20101001',0.08);INSERT INTO TD VALUES (412,002,'20090101',0.09);INSERT INTO TD VALUES (412,002,'20100901',0.04); I don't know if those are the right things to do. The first change because I thought 577 is associated with 411 and 01 rather than 411 and 02.The second change because the dates for 578 start in 20090101, so the way the code is written, it expects to find a CatStartDate earlier than or equal to that date.
Thanks again, that is great point, I will spot check the data in TD vs. TA. And also run againist test production data |
 |
|
|
sunitabeck
Master Smack Fu Yak Hacker
5155 Posts |
Posted - 2011-04-18 : 16:07:05
|
| If you do have periods for which you don't have CatRate, that can be taken into account if you have a business rule that will allow for that. For example, in that case you might say that you want to use the earliest date that is available even if it is after the month for which you are doing the calculations.Alternatively, you might say that if there is no CatRate for a period, then don't apply the CatRate at all for those months. |
 |
|
|
dz0001
Starting Member
35 Posts |
Posted - 2011-04-20 : 10:51:22
|
| Sunita,I run against small sample of production data, it works great so far. I do have one question, how do I store the result of data set, currently everything is returned from CTE, obviously I would like to store in the table. I probably run this once a month.Also I start to get "max recursion 100 has been exhausted before statement completion" again when I try to run against all data, the eariest data is 03/18/2000, so 150 of maxrecursion should do it. I try to add table hintSELECT * FROM CTE ORDER BY SID, Duedate option (MAXRECURSION 150);But it seems not workingThanksDon |
 |
|
|
Next Page
|
|
|