Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
Author |
Topic |
tishri
Yak Posting Veteran
95 Posts |
Posted - 2007-07-06 : 06:26:55
|
declare @tmp_table table(account_no int, balance smallmoney, last_charged smalldatetime, monthlycharge smallmoney)insert into @tmp_tableselect 5 as account_no, 1050 as balance, '07/07/2006' as last_charged , 350 as monthlycharge union all select 8,370, '09/07/2006' ,350.50 union all select 10,2000, '07/15/2006',500 union all select 11,750.50, '07/12/2006',350.50--if balance / monthlycharge has remainder then -- set the remainder as the last_date_charged unpaid amount select * , convert(int,(balance / monthlycharge)) + case when (cast(balance as int) % cast(monthlycharge as int)) > 0 then 1 else 0 end as number_of_months , round(((balance / monthlycharge) - convert(int, balance / monthlycharge) ) * monthlycharge,2) as last_charged_unpaid_amount from @tmp_table t/*account_no balance last_charged monthlyCharge number_of_months last_charged_unpaid_amount---------- ------- ------------------- ------------- ---------------- --------------------------5 1050.0000 2006-07-07 00:00:00 350.0000 3 .0000 8 370.0000 2006-07-07 00:00:00 350.5000 1 19.4900 10 2000.0000 2006-07-15 00:00:00 500.0000 4 .0000 11 750.5000 2006-07-12 00:00:00 350.5000 2 49.4900 if last_charged_unpaid_amount not equal to zero then the first value for date_charged will be equal to last_charged and amount_charged will be equal to last_charged_unpaid_amountelse increment last_charged by 1 month and amount_charged will be equal to monthlychargeto produce a result like thisaccount_no balance last_charged monthlyCharge number_of_months_covered last_charged_unpaid_amount date_charged amount_charged---------- ------- ------------------- ------------- ------------------------ -------------------------- ------------ --------------5 1050.0000 2006-07-07 00:00:00 350.0000 3 .0000 2006-08-07 00:00:00 350.00005 1050.0000 2006-07-07 00:00:00 350.0000 3 .0000 2006-09-07 00:00:00 350.00005 1050.0000 2006-07-07 00:00:00 350.0000 3 .0000 2006-10-07 00:00:00 350.00008 370.0000 2006-09-07 00:00:00 350.5000 2 19.4900 2006-09-07 00:00:00 19.49008 370.0000 2006-09-07 00:00:00 350.5000 2 19.4900 2006-10-07 00:00:00 350.500010 2000.0000 2006-07-15 00:00:00 500.0000 4 .0000 2006-08-15 00:00:00 500.000010 2000.0000 2006-07-15 00:00:00 500.0000 4 .0000 2006-09-15 00:00:00 500.000010 2000.0000 2006-07-15 00:00:00 500.0000 4 .0000 2006-10-15 00:00:00 500.000010 2000.0000 2006-07-15 00:00:00 500.0000 4 .0000 2006-11-15 00:00:00 500.000011 750.5000 2006-07-12 00:00:00 350.5000 3 49.4900 2006-07-12 00:00:00 49.000011 750.5000 2006-07-12 00:00:00 350.5000 3 49.4900 2006-08-12 00:00:00 350.500011 750.5000 2006-07-12 00:00:00 350.5000 3 49.4900 2006-09-12 00:00:00 350.5000and by getting only the necessary fields it would result like this.The result below is the final result that i would like to gather. You can also suggest another approach so thati can derive the result below based on the table values given above.account_no date_charged amount_charged---------- ------------ --------------5 2006-08-07 00:00:00 350.00005 2006-09-07 00:00:00 350.00005 2006-10-07 00:00:00 350.00008 2006-09-07 00:00:00 19.49008 2006-10-07 00:00:00 350.500010 2006-08-15 00:00:00 500.000010 2006-09-15 00:00:00 500.000010 2006-10-15 00:00:00 500.000010 2006-11-15 00:00:00 500.000011 2006-07-12 00:00:00 49.000011 2006-08-12 00:00:00 350.500011 2006-09-12 00:00:00 350.5000*/ TCC |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 07:11:00
|
Try this. I can't test it right now as I don't have SQL Server 2005 nearby.-- prepare sample datadeclare @sample table(account_no int, balance smallmoney, last_charged smalldatetime, monthlycharge smallmoney)insert @sample (account_no, balance, last_charged, monthlycharge)select 5, 1050, '07/07/2006', 350 union allselect 8, 370, '09/07/2006', 350.50 union allselect 10, 2000, '07/15/2006', 500 union allselect 11, 750.50, '07/12/2006', 350.50--show the expected outputselect s.account_no, s.balance, dateadd(month, d.number, s.last_charged) as last_charged, s.monthlychargefrom @sample as scross apply ( select number from master..spt_values where number between 1 and floor(s.balance / s.monthlycharge) and type = 'p' ) AS dwhere floor(s.balance / s.monthlycharge) > 0union allselect account_no, balance, last_charged, balance - monthlycharge * floor(balance / monthlycharge)from @samplewhere balance - monthlycharge * floor(balance / monthlycharge) > 0order by account_no, last_charged Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
|
Ifor
Aged Yak Warrior
700 Posts |
Posted - 2007-07-06 : 07:41:29
|
orSELECT account_no ,CASE WHEN D.last_charged_unpaid_amount <> 0.0 THEN DATEADD(month, N.N - 1, D.last_charged) ELSE DATEADD(month, N.N, D.last_charged) END AS date_charged ,CASE WHEN D.last_charged_unpaid_amount <> 0.0 THEN CASE N.N WHEN 1 THEN D.last_charged_unpaid_amount ELSE D.monthlycharge END ELSE D.monthlycharge ENDFROM ( SELECT T.* ,CAST(T.balance/T.monthlycharge AS int) + CASE WHEN CAST(T.balance AS int) % cast(T.monthlycharge AS int) > 0 THEN 1 ELSE 0 END AS number_of_months , ROUND((T.balance/T.monthlycharge - CAST(T.balance/T.monthlycharge AS int)) * T.monthlycharge, 2) AS last_charged_unpaid_amount FROM @tmp_table T ) D JOIN ( SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 -- etc ) N (N) -- or use Number/Tally table ON N.N <= D.number_of_months |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 07:57:43
|
quote: Originally posted by Ifor
JOIN ( SELECT 1 as n UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 -- etc ) N (N) -- or use Number/Tally table ON N.N <= D.number_of_months
Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 08:17:00
|
Ifor, try this test data. it will not function correctly.select 99, 100, '07/15/2006', 34 union all Do you have SQL Server 2005? Try my suggestion with this test data too, please.Peter LarssonHelsingborg, Sweden |
 |
|
Ifor
Aged Yak Warrior
700 Posts |
Posted - 2007-07-06 : 09:24:44
|
Peso,1. I do not seem to need to put 'as n' in the derived table as long as I put '(N)' after the alias.2. Thanks for providing data that points out my logic error.When I replace all occurances of CAST(T.balance/T.monthlycharge AS int) with FLOOR(T.balance/T.monthlycharge) my query produces the desired results.3. When I tried the queries in SQL2005, on a desktop machine, the execution plan produced the following querty costs relative to the batch:a) Create Test Data - 17%b) My altered query - 6%c) Your query - 78% |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 10:13:03
|
Slightly different if you also put an order by to your query Still in your favor though!Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 10:16:07
|
And try this test dataselect 99, 7, '07/15/2006', 3.50 union all Peter LarssonHelsingborg, Sweden |
 |
|
Ifor
Aged Yak Warrior
700 Posts |
Posted - 2007-07-06 : 10:45:31
|
Peso,A good point about the ORDER BY.quote: select 99, 7, '07/15/2006', 3.50 union all
OK! The WHEN CAST(T.balance AS int) % cast(T.monthlycharge AS int) > 0should be WHEN T.balance % T.monthlycharge > 0.0.(A lesson in not mindlessly copying someone else's logic! ) |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 10:55:19
|
And replacing your hardcoded tally table with the use of master..spt_values (or changing my query to hardcoded tally table) changed the scene.Now both are 50% each!--show the expected output with improved algorithm for SQL Server 2000select s.account_no, dateadd(month, d.number, s.last_charged) as last_charged, case when d.number = 0 and s.balance > s.monthlycharge * floor(s.balance / s.monthlycharge) then s.balance - s.monthlycharge * floor(s.balance / s.monthlycharge) when d.number > 0 then s.monthlycharge end as monthlychargefrom @sample as sinner join ( select number from master..spt_values where number between 0 and 4 and type = 'p' ) AS d ON d.number <= floor(s.balance / s.monthlycharge)where balance > monthlycharge * floor(balance / monthlycharge) or d.number > 0order by 1, 2--show the expected output with improved algorithm for SQL Server 2005select s.account_no, dateadd(month, d.number, s.last_charged) as last_charged, case when d.number = 0 and s.balance > s.monthlycharge * floor(s.balance / s.monthlycharge) then s.balance - s.monthlycharge * floor(s.balance / s.monthlycharge) when d.number > 0 then s.monthlycharge end as monthlychargefrom @sample as scross apply ( select number from master..spt_values where number between 0 and floor(s.balance / s.monthlycharge) and type = 'p' ) AS dwhere balance > monthlycharge * floor(balance / monthlycharge) or d.number > 0order by 1, 2 I could not test my SQL Server 2005 query.Peter LarssonHelsingborg, Sweden |
 |
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2007-07-06 : 10:57:04
|
quote: Originally posted by Ifor The WHEN CAST(T.balance AS int) % cast(T.monthlycharge AS int) > 0should be WHEN T.balance % T.monthlycharge > 0.0.
This does not work for smallmoney datatype.Peter LarssonHelsingborg, Sweden |
 |
|
tishri
Yak Posting Veteran
95 Posts |
Posted - 2007-07-06 : 21:08:36
|
yeah perfect guys!!TCC |
 |
|
|
|
|
|
|