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 |
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-11 : 23:44:52
|
Hi,I need some help calculating a rolling 3 month average cost from the two dataset below. Which is the 3 month Average of Dataset1 / Dataset 2. Thanks.Dataset 1:SELECT(factAdmissions.ContractCode + '-' +factAdmissions.BenefitPlanCode) AS [Contract Code],factAdmissions.AdmitCCYYMM,ISNULL(sum(AmountPaid),0)As [Amount Paid]FROM factAdmissionsWHERE factAdmissions.AdmitCCYYMM >='200701'AND factAdmissions.AcuteSNFIndAdmit ='a'AND factAdmissions.ContractCode Is Not NullAND factAdmissions.BenefitPlanCode Is Not NullAND BusinessUnitCode In('EP','HF', 'VN')AND AdmitCCYYMM BETWEEN (@StartDate) AND (@EndDate)AND factAdmissions.ContractCode + '-' +factAdmissions.BenefitPlanCode IN (@Product)Group by factAdmissions.ContractCode, factAdmissions.BenefitPlanCode, factAdmissions.AdmitCCYYMMOrder by factAdmissions.ContractCode, factAdmissions.BenefitPlanCode, factAdmissions.AdmitCCYYMM;Dataset2: Select (factMembership.ContractCode+'-'+ factMembership.BenefitPlanCode) As Product, EffectiveCCYYMM, ISNULL(count(Distinct MemberId),0) As MemberCount From factMembership Where EffectiveCCYYMM >= '200701'AND BusinessUnitCode In('EP','HF', 'VN')AND EffectiveCCYYMM BETWEEN (@StartDate) AND (@EndDate)AND factMembership.ContractCode + '-' +factMembership.BenefitPlanCode IN (@Product) Group by ContractCode, BenefitPlanCode, EffectiveCCYYMM Order by 1; |
|
divya.ce
Starting Member
16 Posts |
Posted - 2013-09-12 : 07:24:06
|
It will be good if you give the sample output of the datasets as well as the output you require. |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-12 : 09:22:16
|
quote: Originally posted by divya.ce It will be good if you give the sample output of the datasets as well as the output you require.
Dataset 1: Output 201101 201102 201103Cost $420,627 $73,608 $93,792 Dataset 2:Output 201103Memberscount 400 Desired Output: 201103 3 Month Rolling Average $490.02 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2013-09-12 : 16:08:47
|
why are you bringing it in different datasets? why cant they all be calculated in same dataset?Also I didnt understand how you got $490.02 as monthly avg for prev 3 months. can you explain?------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-12 : 16:58:59
|
Well, I need a rolling 3 month average cost from dataset 1, which is my cost dataset. Dataset 2 is the count of members. I got $490.02 by taking the 3 month average cost and dividing it by count of members. This is a standard healthcare insurance metric. This may not be the right approach with both dataset, so please advise.quote: Originally posted by visakh16 why are you bringing it in different datasets? why cant they all be calculated in same dataset?Also I didnt understand how you got $490.02 as monthly avg for prev 3 months. can you explain?------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs
|
|
|
James K
Master Smack Fu Yak Hacker
3873 Posts |
Posted - 2013-09-12 : 17:32:04
|
Since I don't have access to your data and tables or any knowledge of the schema, I am unable to offer specifics. But in general, the query below shows how you would do it.In cte1, I am calculating two columns: 1, the cost for a given month, and 2, the beginning of that month (so I can associate the cost with a month)In cte2, I am calculating two columns: 1, the average number of members, and 2, the beginning of that month (so I can associate the member count with a month).Now that I have those two tables, I joining the two tables, but also joining to cte1 two more times to pick up the values from the prior two months.This is only a template. You will need to refine it - for example, if there is no data for any of the 3 months how that should be handled etc.;WITH cte1 AS ( SELECT SUM(cost) AS cost, beginningOfMonthDate FROM SomeTable GROUP BY beginningOfMonthDate),cte2 AS( SELECT AVG(numberofMembers) AS numberofMembers, beginningofMonthDate FROM AnotherTable GROUP BY beginningOfMonthDate)SELECT (COALESCE(a1.Cost,0) + COALESCE(a2.cost,0) + COALESCE(a3.cost,0))/(3.0*b.numberofMembers)FROM cte1 a1 INNER JOIN cte2 b ON a1.beginningOfMonthDate = b.beginningOfMonthDate LEFT JOIN cte1 a2 ON a1.beginningOfMonthDate = DATEADD(mm,1,a2.beginningOfMonthDate) LEFT JOIN cte1 a3 ON a1.beginningOfMOnthDate = DATEADD(mm,2,a3.beginningOfMonthDate) |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2013-09-12 : 17:41:13
|
Are you using SQL Server 2012? Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-12 : 23:59:06
|
Sql Server 2008. quote: Originally posted by SwePeso Are you using SQL Server 2012? Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA
|
|
|
divya.ce
Starting Member
16 Posts |
Posted - 2013-09-13 : 07:18:46
|
One question, can you expand your dataset to give how the rolling average should behave? in your current output you have given fixed output for 3 months, if in case it has more months, how do you need the output to be? Datasets eg are given below, Dataset 1: Output dt cost 201101 $420,627201102 $73,608201103 $93,792201104 $234201105 $23424201106 $5454201107 $5454 Dataset 2:Output dt Memberscount 201101 400201102 100201103 40201104 30201105 560201106 100Desired output?? |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-14 : 00:40:29
|
The examples below would replicate an excel formula where the formula moves one cell over to calculate the 3 month Average.Dataset1AmoutPaid:201102 $73,608201103 $93,792201104 $234Dataset2Memberscount:201104 303 month Average cost = $1,863. ---------------------------------------------Dataset1AmoutPaid:201103 $93,792201104 $234201105 $23424 Dataset2Memberscount:201105 5603 month Average cost = $69.91 ----------------------------------------------Dataset1AmoutPaid:201104 $234 201105 $23,424 201106 $5,454 Dataset2Memberscount:201106 1003 month Average cost $97.04 -------------------------------------------quote: Originally posted by divya.ce One question, can you expand your dataset to give how the rolling average should behave? in your current output you have given fixed output for 3 months, if in case it has more months, how do you need the output to be? Datasets eg are given below, Dataset 1: Output dt cost 201101 $420,627201102 $73,608201103 $93,792201104 $234201105 $23424201106 $5454201107 $5454 Dataset 2:Output dt Memberscount 201101 400201102 100201103 40201104 30201105 560201106 100Desired output??
|
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-14 : 00:56:37
|
Thanks for your input. However,I tried your suggested code and got this error: "Msg 242, Level 16, State 3, Line 2The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.Warning: Null value is eliminated by an aggregate or other SET operation."quote: Originally posted by James K Since I don't have access to your data and tables or any knowledge of the schema, I am unable to offer specifics. But in general, the query below shows how you would do it.In cte1, I am calculating two columns: 1, the cost for a given month, and 2, the beginning of that month (so I can associate the cost with a month)In cte2, I am calculating two columns: 1, the average number of members, and 2, the beginning of that month (so I can associate the member count with a month).Now that I have those two tables, I joining the two tables, but also joining to cte1 two more times to pick up the values from the prior two months.This is only a template. You will need to refine it - for example, if there is no data for any of the 3 months how that should be handled etc.;WITH cte1 AS ( SELECT SUM(cost) AS cost, beginningOfMonthDate FROM SomeTable GROUP BY beginningOfMonthDate),cte2 AS( SELECT AVG(numberofMembers) AS numberofMembers, beginningofMonthDate FROM AnotherTable GROUP BY beginningOfMonthDate)SELECT (COALESCE(a1.Cost,0) + COALESCE(a2.cost,0) + COALESCE(a3.cost,0))/(3.0*b.numberofMembers)FROM cte1 a1 INNER JOIN cte2 b ON a1.beginningOfMonthDate = b.beginningOfMonthDate LEFT JOIN cte1 a2 ON a1.beginningOfMonthDate = DATEADD(mm,1,a2.beginningOfMonthDate) LEFT JOIN cte1 a3 ON a1.beginningOfMOnthDate = DATEADD(mm,2,a3.beginningOfMonthDate)
|
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2013-09-15 : 03:45:24
|
quote: Originally posted by Briceston Thanks for your input. However,I tried your suggested code and got this error: "Msg 242, Level 16, State 3, Line 2The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.Warning: Null value is eliminated by an aggregate or other SET operation."quote: Originally posted by James K Since I don't have access to your data and tables or any knowledge of the schema, I am unable to offer specifics. But in general, the query below shows how you would do it.In cte1, I am calculating two columns: 1, the cost for a given month, and 2, the beginning of that month (so I can associate the cost with a month)In cte2, I am calculating two columns: 1, the average number of members, and 2, the beginning of that month (so I can associate the member count with a month).Now that I have those two tables, I joining the two tables, but also joining to cte1 two more times to pick up the values from the prior two months.This is only a template. You will need to refine it - for example, if there is no data for any of the 3 months how that should be handled etc.;WITH cte1 AS ( SELECT SUM(cost) AS cost, beginningOfMonthDate FROM SomeTable GROUP BY beginningOfMonthDate),cte2 AS( SELECT AVG(numberofMembers) AS numberofMembers, beginningofMonthDate FROM AnotherTable GROUP BY beginningOfMonthDate)SELECT (COALESCE(a1.Cost,0) + COALESCE(a2.cost,0) + COALESCE(a3.cost,0))/(3.0*b.numberofMembers)FROM cte1 a1 INNER JOIN cte2 b ON a1.beginningOfMonthDate = b.beginningOfMonthDate LEFT JOIN cte1 a2 ON a1.beginningOfMonthDate = DATEADD(mm,1,a2.beginningOfMonthDate) LEFT JOIN cte1 a3 ON a1.beginningOfMOnthDate = DATEADD(mm,2,a3.beginningOfMonthDate)
Thats because one or more of your beginningOfMonthDate fields is not of datetime type and has values in all the different formatsseehttp://visakhm.blogspot.in/2011/12/why-iso-format-is-recommended-while.html------------------------------------------------------------------------------------------------------SQL Server MVPhttp://visakhm.blogspot.com/https://www.facebook.com/VmBlogs |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2013-09-15 : 14:01:49
|
[code]DECLARE @Costs TABLE ( Period INT NOT NULL, Cost INT NOT NULL );INSERT @Costs ( Period, Cost )VALUES (201101, 420627), (201102, 73608), (201103, 93792), (201104, 234), (201105, 23424), (201106, 5454), (201107, 5454);DECLARE @Members TABLE ( Period INT NOT NULL, Number INT NOT NULL );INSERT @Members ( Period, Number )VALUES (201101, 400), (201102, 100), (201103, 40), (201104, 30), (201105, 560), (201106, 100);-- SwePeso (pre SQL Server 2012)SELECT c.Period, f.Average / m.Number AS MovingAverageFROM @Costs AS cCROSS APPLY ( SELECT AVG(Cost) AS Average FROM ( SELECT TOP(3) x.Cost FROM @Costs AS x WHERE x.Period <= c.Period ORDER BY x.Period DESC ) AS d ) AS fINNER JOIN @Members AS m ON m.Period = c.PeriodORDER BY c.Period;-- SwePeso (SQL Server 2012 and 2014)SELECT c.Period, AVG(c.Cost) OVER (ORDER BY c.Period ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) / m.Number AS MovingAverageFROM @Costs AS cINNER JOIN @Members AS m ON m.Period = c.PeriodORDER BY c.Period;[/code] Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-16 : 13:08:36
|
SwePeso, thanks for the below example. However, this does not calculate a rolling 3 month average. I'm looking to take the average of every three months and divide it by the count of members by the month.Your result set below calculates one months cost and divides it by the count of member for that period.Result from SwePeso:Period MovingAverage201101 1051201102 2471201103 4900201104 1862201105 69201106 97 quote: Originally posted by SwePeso
DECLARE @Costs TABLE ( Period INT NOT NULL, Cost INT NOT NULL );INSERT @Costs ( Period, Cost )VALUES (201101, 420627), (201102, 73608), (201103, 93792), (201104, 234), (201105, 23424), (201106, 5454), (201107, 5454);DECLARE @Members TABLE ( Period INT NOT NULL, Number INT NOT NULL );INSERT @Members ( Period, Number )VALUES (201101, 400), (201102, 100), (201103, 40), (201104, 30), (201105, 560), (201106, 100);-- SwePeso (pre SQL Server 2012)SELECT c.Period, f.Average / m.Number AS MovingAverageFROM @Costs AS cCROSS APPLY ( SELECT AVG(Cost) AS Average FROM ( SELECT TOP(3) x.Cost FROM @Costs AS x WHERE x.Period <= c.Period ORDER BY x.Period DESC ) AS d ) AS fINNER JOIN @Members AS m ON m.Period = c.PeriodORDER BY c.Period;-- SwePeso (SQL Server 2012 and 2014)SELECT c.Period, AVG(c.Cost) OVER (ORDER BY c.Period ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) / m.Number AS MovingAverageFROM @Costs AS cINNER JOIN @Members AS m ON m.Period = c.PeriodORDER BY c.Period; Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA
|
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2013-09-16 : 13:54:17
|
Where do you think the number of 1862 comes from?I believe the number of 1862 is the average from the three months 201302 to 201304 (73608+93792+234) which averages to 55878.Then I believe the average number of 55787 is divided by the number of members for 201304 (30) to result in 1862.What do you believe? Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-16 : 15:31:07
|
SwePeso, My bad, I apologize your code is correct. I mistakenly caluclated against the wrong cells in excel when I was verifying your result set. My apologize once again.The data used was a sample, how would I use the results from dataset1 and dataset2 to get the final result? Without having to do a insert value.quote: Originally posted by SwePeso Where do you think the number of 1862 comes from?I believe the number of 1862 is the average from the three months 201302 to 201304 (73608+93792+234) which averages to 55878.Then I believe the average number of 55787 is divided by the number of members for 201304 (30) to result in 1862.What do you believe? Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA
|
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2013-09-17 : 00:29:45
|
[code]-- SwePeso (pre SQL Server 2012)SELECT c.Period, f.Average / m.Number AS MovingAverageFROM {Your Cost Table Schema Here}.{Your Cost Table Name Here} AS cCROSS APPLY ( SELECT AVG(1E * Cost) AS Average FROM ( SELECT TOP(3) x.Cost FROM {Your Cost Table Schema Here}.{Your Cost Table Name Here} AS x WHERE x.Period <= c.Period ORDER BY x.Period DESC ) AS d ) AS fINNER JOIN {Your Member Table Schema Here}.{Your Member Table Name Here} AS m ON m.Period = c.PeriodORDER BY c.Period;[/code] Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA |
|
|
Briceston
Yak Posting Veteran
54 Posts |
Posted - 2013-09-18 : 01:02:48
|
I used my table and the actual fields within the below example, but my result set was wrong. I think reason it's off is the AmountPaid field should be sum first then Average, and the Memberid is a count of the Member id. When I tried these updates I got syntax errors.SELECT c.AdmitCCYYMM, f.Average / m.MemberId AS MovingAverageFROM factAdmissions AS cCROSS APPLY ( SELECT AVG(1E * AmountPaid) AS Average FROM ( SELECT TOP(3) x.AmountPaid FROM factAdmissions AS x WHERE x.AdmitCCYYMM <= c.AdmitCCYYMM ORDER BY x.AdmitCCYYMM DESC ) AS d ) AS fINNER JOIN factMembership AS m ON m.EffectiveCCYYMM = c.AdmitCCYYMMORDER BY c.AdmitCCYYMM;Result set from query: About 278,000 Rows of the samething. AdmitCCYYMM MovingAverage200701 0.0122584090551209200701 0.0122584090551209200701 0.0122584090551209200701 0.0122584090551209200701 0.0122584090551209200701 0.0122584090551209200701 0.0122584090551209quote: Originally posted by SwePeso
-- SwePeso (pre SQL Server 2012)SELECT c.Period, f.Average / m.Number AS MovingAverageFROM {Your Cost Table Schema Here}.{Your Cost Table Name Here} AS cCROSS APPLY ( SELECT AVG(1E * Cost) AS Average FROM ( SELECT TOP(3) x.Cost FROM {Your Cost Table Schema Here}.{Your Cost Table Name Here} AS x WHERE x.Period <= c.Period ORDER BY x.Period DESC ) AS d ) AS fINNER JOIN {Your Member Table Schema Here}.{Your Member Table Name Here} AS m ON m.Period = c.PeriodORDER BY c.Period; Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA
|
|
|
divya.ce
Starting Member
16 Posts |
Posted - 2013-09-18 : 03:53:00
|
Hey Briceston, If you want the result to behave like the rolling average in excel, please read my article on the same. i have faced a similar situation earlier. Link to the article: http://www.sqlservercentral.com/articles/Iterative/64699/ Let me if it helped you. |
|
|
zhaodandan
Starting Member
3 Posts |
Posted - 2013-09-18 : 04:10:06
|
unspammed |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2013-09-18 : 04:20:15
|
Look at your query. You did something very wrong when adapting it to your environment.SELECT c.AdmitCCYYMM, f.Average / m.MemberID AS MovingAverage --< What is wrong here?FROM dbo.factAdmissions AS cCROSS APPLY ( SELECT AVG(1E * AmountPaid) FROM ( SELECT TOP(3) x.AmountPaid FROM dbo.factAdmissions AS x WHERE x.AdmitCCYYMM <= c.AdmitCCYYMM ORDER BY x.AdmitCCYYMM DESC ) AS d ) AS f(Average)INNER JOIN factMembership AS m ON m.EffectiveCCYYMM = c.AdmitCCYYMMORDER BY c.AdmitCCYYMM; Why divide by m.MemberID? Aren't you supposed to divide by m.MemberCount or similar? A value that actually changes for every month? Microsoft SQL Server MVP, MCT, MCSE, MCSA, MCP, MCITP, MCTS, MCDBA |
|
|
Previous Page&nsp;
Next Page
|
|
|
|
|