Showing posts with label age. Show all posts
Showing posts with label age. Show all posts

Friday, March 30, 2012

Grouping question...

Hi,

I am migrating some reports from MS Access2003 to SQL 2005 Reporting Services.

I have a dataset which contains columns for Sex, Age, Name etc... I firstly display the contents of this dataset in a table and this is fine. I also need to display a table of the breakdown of the age and sex. E.G:-

< 16yrs 16yrs-24yrs 25yrs-64yrs 65yrs-74yrs 75yrs-84yrs >=85yrs
Male x x x x x x

Female x x x x x x

Does anyone know if this is possible. I was going to use a DCount function (As found in access) but I can not find it in SRS. What is thet best way to produce this result?

Thanks in advance for your time

Peter Tewkesbury

BlueFlower Limited

Conditional aggregation can be achieved as follows:

=Sum(iif(Fields!Age.Value >= 25 AND Fields!Age.Value < 65, 1, 0))

-- Robert

sql

Monday, March 26, 2012

Grouping Dimension Values

I have a question about grouping values in a dimension.

I have a dimension that relates to the age of a person. When I run my ETL we bring in the age as it was at the time of the load. When I display that age to my users in a report, I would like to group the ages according to internal usages.

Example: Age 16, 17, 18 would be grouped into a group of 16 to 18, etc....

This provides to us a larger statistic sample set, plus it makes the reports much easier to read.

I am using Reporting Services to generate reports, but I was looking to move the grouping logic away from the client to the Analysis Services server.

I actually have several dimensions like this where I would like to perform grouping.

I was considering using a Calculated Member to solve this, but wasn't sure if there was a cleaner solution.

Thanks in advance.

Bill

One solution is to do this by a named calculation in the data source view and create your groups with TSQL-CASE. In this way you will have full control over the groups.

The other way is to use the discretization method property of this attribute/column in the dimension editor. With this method you let SSAS create the groups with a little less flexibility than using a named calculation.

HTH

Thomas Ivarsson

|||

Thomas,

Thanks for the response.

I should have stated in my initial post that I am using AS 2000 not SSAS 2005.

Sorry for that.

Any ideas as to how to fix this solution into AS 2000?

Thanks in advance

Bill

|||

Use TSQL Case when you update your dimension table. Books On Line have good examples regarding case.

You can also wrap the TSQL case in you key and name columns, for the dimension level, in the dimension editor. This more of a dirty hack than fixing this in the dimension and your data source.

You can use views against the source table as well.

HTH

Thomas Ivarsson

Friday, March 23, 2012

Grouping by Age

I have a table Age and need to create Report by Grouping Salesfigures according to Age.
I put the following expression into Grouping and Sorting Properties/General/Filter /Sorting Expression... as well as in Textbox Properties/ values..

=IIF(Fields!Age.Value < 16, "<16",IIF(Fields!Age.Value <21,"16-20")

Errormessage: Value expression for textbox "Age" error: Argument not specified for parameter 'FalsePart' of 'Public function IIF(Expression as Boolean, TruePart as Object, Falsepart As Object) As Object'.

Question 2 .
How to return Month as January, February... In correct order?
"DATENAME(mm, Sales.time) AS Month" (Ascending ) returns starting with April, August...
DATEPART(mm, Sales.time) AS Month (Ascending ) returns starting with 1, 10, 11 ...

Answer 1

Your expression is incomplete. As the error message says, you are missing the FlasePart of the nested Iif function, as well a parentheses

=IIF(Fields!Age.Value < 16, "<16",IIF(Fields!Age.Value <21,"16-20", ">20" ) )

Can you clarify Quaestion 2. E.g. where are you putting this code, can you paste your query?

|||

For Question 1 you don't have a false path to follow in your second iif.

=IIF(Fields!Age.Value < 16, "<16",IIF(Fields!Age.Value <21,"16-20",""))

|||Thank you so much!

SELECT SUM(Cd.Price) AS Sales, DATENAME(mm, Purchase.time) AS Month, Staff.Name
FROM Staff INNER JOIN
Purchase ON Staff.Staff_id = Purchase.Salesperson_id INNER JOIN
Cd ON Purchase.Cd_id = Cd.Cd_id
GROUP BY DATENAME(mm, Purchase.time), Staff.Name
ORDER BY Month Asc

The outcome is starting with April...
(not with January)?|||Thank you.. still, "Argument not specified for false part". Something I've misunderstood?

=IIF(Fields!Age.Value < 16, "<16",IIF(Fields!Age.Value <21,"16-20"),IIF(Fields!Age.Value <31,"21-30"), IIF(Fields!Age.Value < 41,"31-40"),IIF(Fields!Age.Value <51,"41-50",">50"))

I put this value expression In textbox "Age"/Expression, as well as in Grouping Sorting properties /General/Filter/ Sorting|||

Yes you have misunderstood this slightly. The definition of the Iif function is

Iif(<<condition>>, TruePart, FalsePart)

Your expression puts many Iif's all passed into a single Iif. You actually have to nest the Iif's as the FalsePart of the previous Iif

Your expression:
=IIF
( Fields!Age.Value < 16 <- condition
, "<16" <- TruePart
, IIF(Fields!Age.Value <21,"16-20") <- FalsePart nested IIF
, IIF(Fields!Age.Value <31,"21-30") <- Error 4th argument
, IIF(Fields!Age.Value <41,"31-40") <- Error 5th argument
, IIF(Fields!Age.Value <51,"41-50",">50") <- Error 6th argument
)

Correct Expression:
=IIF
( Fields!Age.Value < 16 <- condition
, "<16" <- TruePart
, IIF <- FalsePart nested IIF
( Fields!Age.Value < 21 <- condition
,"16-20" <- TruePart
, IIF <- FalsePart nested IIF
( Fields!Age.Value < 31 <- condition
, "21-30" <- TruePart
, IIF <- FalsePart nested IIF
( Fields!Age.Value < 41 <- condition
, "31-40" <- TruePart
, IIF <- FalsePart nested IIF
( Fields!Age.Value < 51 <- condition
, "41-50" <- TruePart
, ">50" <- FalsePart
)
)
)
)
)

just make sure you get the parentheses right and you remove the comments

|||

As far as your query goes, display the name but order by number. for this to work you must include both in the GROUP BY clause

SELECT SUM(Cd.Price) AS Sales, DATENAME(mm, Purchase.time) AS Month, Staff.Name
FROM Staff INNER JOIN
Purchase ON Staff.Staff_id = Purchase.Salesperson_id INNER JOIN
Cd ON Purchase.Cd_id = Cd.Cd_id
GROUP BY DATENAME(mm, Purchase.time)
, DATEPART(mm, Purchase.time)
, Staff.Name
ORDER BY DATEPART(mm, Purchase.time) Asc

|||

Would it be possible to create a field from a select e.g.

SELECT Age, AgeGroup =

CASE

WHEN (age >= 1 and age <= 3) THEN 'Age 1-3'

WHEN (age >= 4 and age <= 5) THEN 'Age 4-5'

WHEN (age >= 6 and age <= 7) THEN 'Age 6-7'

ELSE 'Over age'

END

FROM tblAge

|||In fact, I prefer this option, give RS less work to do.

Monday, March 19, 2012

Group members of a derived dimension

Hi, Have created a dimension based on a column in the FACT, called Age as given in the post (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=199100&SiteID=1) . Now, I need to group these members in custom buckets. The 'aggregate*' property is not allowing for custom buckets. Since this is a derived dimension, it is not appearing in the list of dimensions under the 'Create Custom Member formula' under 'Add BI' feature. How to accomplish this?

Secondly, If I try to create a calculated member on this dimension, why should it be attached under an existing attribute? So, even this route didnt work.

Thanks ina dvance,

If you followed the steps in that post, what you created in the fact table with your case statement is a set of derived surrogate keys. You would then link these keys to a dimension created from a table/view in your dsv. In this dimension table you could then add an extra column for a grouping and specify the group for each member.

Friday, February 24, 2012

Group age by a parameter and find out the value corresponding to that.

Hi guys...

My goal is to change the given stored procedure so that I can find out the different age gorup according to users parameter and find out sumof these values for that group:
s.TVmins, s.Notional$, COUNT(*) AS Qty, SUM(s.TVmins) AS TVMinsAmt, SUM(s.Notional$) AS NotionalAmt
For that I am planning to put another parameter @.count for the group interval and I need to group accordingly.
So my answer should look like:
if the user give the @.count value as 10:
the result should:

age group TVMins Notional

1-9 1560 125632( the sum of that particluar group)
10-19 -- --

91-100 --

I have a field DOB( Date of birth) , I have to extract age from that field first and then group them according to the parameter values and then find its corresponding sums...

<CODE>

--
ALTER PROCEDURE [dbo].[sp_PlanningData]
@.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'SELECT
dm.DOB,
dm.Suburb,
vs.RID,
s.TVmins,
s.Notional$,
COUNT(*) AS Qty,
SUM(s.TVmins) AS TVMinsAmt,
SUM(s.Notional$) AS NotionalAmt

FROM dbo.lkpService s
INNER JOIN dbo.tmpValidServices_ALL vs ON s.Code = vs.Service
INNER JOIN dbo.tmpDemographics_ALL dm ON dm.RID = vs.RID '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpCOC c ON vs.COC = c.pvcode '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpAgency ag ON vs.SiteID = ag.EXACT# '

SELECT @.sql = @.sql + 'WHERE s.Schedule = @.Schedule '

IF @.StartDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete >= @.StartDate ) '

IF @.EndDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete <= @.EndDate ) '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + ' AND (ag.AgencyTypeID = @.ProgrammeID)'

IF @.SiteID IS NOT NULL
SELECT @.sql = @.sql + 'AND (ag.EXACT# = @.SiteID) '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + ' AND (c.pvcode = @.COCGroup OR c.pvcode IN (SELECT COC FROM lkpCOCGroup WHERE COCGroup = @.COCGroup)) '

IF @.Provider IS NOT NULL
SELECT @.sql = @.sql + 'AND (vs.Provider = @.Provider) '

SELECT @.sql = @.sql + 'GROUP dm.Suburb,vs.RID, s.TVmins, s.Notional$ '

SELECT @.paramlist =
' @.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime '

EXEC sp_executesql @.sql,@.paramlist,@.ProgrammeID,@.RegionID,@.SiteID,@.COCGroup,@.Provider,@.Schedule,@.StartDate,@.EndDate

END
-
</CODE>

Hope this will help.. it is really urgent one.. I am trying my best to find it out..
Thanks for your help..

This will give you the range.

Create Table #Temp(Interval int, MyRange varchar(20))

DECLARE @.MyNewInterval int

DECLARE @.MyNewRange varchar(max)

DECLARE @.Interval int

SET @.INTERVAL = 10 --SET YOUR INTERVAL HERE OR PASS IT IN

SET @.MyNewInterval = 0

While @.MyNewInterval < (1000 + @.Interval)

BEGIN

INSERT INTO #Temp(Interval, MyRange) VALUES(@.MyNewInterval, @.MyNewInterval + @.Interval)

SET @.MyNewInterval = @.MyNewInterval + @.INTERVAL

END

SELECT cast(Interval as varchar(50)) + ' - ' + MyRange AS [Range]

FROM #Temp

drop table #temp

UNION your aggregates and you'll have it

Adamus

|||

Hi,

I can create this range, but how can put it into the proc so that I can get the sum values other fields..

Your help is highly appreciation,

|||

UNION your aggregates

Adamus

|||

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

|||

Here's a method that I think can work for you. (it seems to work anyway)
It allows you to use the size of an interval as a parameter, so that you'll group your ages by, say 10-year groups if you pass in '10', and also lets you extract other values that you can sum, count etc...

Assuming you have a dob in the format of ssyymmdd, then this is a way to calculate the current age:

select cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age

(the cast to int is because we need an int later...)

The idea here is to use MOD as the indicator for how the ages should be grouped.
If we say that we set 10 as the range size, then for each age, the lower bound would be:

age - (age % 10)

and the higher bound would be:

age - (age % 10) + 10

To start, then, you could select the values you want to sum, along with the calculated age.

select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test

Use this is a derived table and find out the low and high ranges for the selected grouping:

declare @.mod int
set @.mod = 10

select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x

Now we can wrap this into yet another derived table and do the final grouping and sum up the values for each group.
It's not entirely necessary to wrap further out, but it keeps the code a bit more readable, since we can group by name instead of repeating the algorithms for low and high..
So the final construct should look something like this;

declare @.mod int
set @.mod = 10

select y.lowrange,
y.highrange,
sum(y.val1) as val1Sum,
sum(y.val2) as val2Sum,
count(*)
from (
select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange

To change the size of the groups, just set @.mod to the desired range, 5, 8, 10, 20 or whatever.

Hope it helps you some.

=;o)
/Kenneth

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

I will give you the answer tomorrow.

Adamus

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

1. Add the one field "Range" in #temp table to your existing table with null values. (allow nulls)
2. Add all fields from your existing table to the #temp table with null values. (allow nulls)

Now you have the same fields in both tables. This is key.

3. Now create your #temp table with only the ranges and populate.
4. UNION ALL your aggregate query.
4b. In your aggregeate query, you'll have to determine which row the aggregate hypothetically will go.
5. You should now have your desired results.

Does this makes sense?

Adamus

|||

Hi Adamus,

I understand what you said. But not sure whether its a good idea to add a new field to the table in my case,

As I added in the first message, I am taking values from different tables and I am unable to add a field to any of the tables due to some security reasons.

Can I add your query into my query or DO the union all ?

I cant resolve this..I am really confused now..

|||

I couldn't quite follow all the twist and turns in the dynamic SQL stuff (not sure that the literal example is actually runnable?), but from what I gathered about the need to produce the age groupings and the two sums and count, I belive that this is about what you need to get those particular items...

You may try and see if it runs on your system.

select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))

Assuming that the above 'base query' is ok for the purpose, the below would (hopefully) group by the age-interval given and sum up the two values according to each group. You may need to declare additional variables @.startdate, @.enddate and @.provider though. The age-intervals returned will be only those where there are ages found in the data, there will be no empty intervals. If that is a requirement (and assuming the whole shebang actually is useful =;o), it's possible to generate empty groups with counts of zero, though that is a bit more code, and also requires a numberstable.
Another assumption is also that DOB is in the format of 'SSYYMMDD'

Anyway, try and see if the below is of any use to you.

-- with ranges contained in data (no empty intervals)
declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

select cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10)) as AgeGroup,
sum(y.TVmins) as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*) as Qty
from (
select x.TVmins,
x.Notional$,
(x.age - (x.age % @.mod)) as lowrange,
(((x.age - (x.age % @.mod)) + @.mod) - 1) as highrange
from (
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))
) x
) y
group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))
order by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Hope it works out for you =;o)

=;o)
/Kenneth

|||

Hi Kenneth,

Thank you very much for your help.

It seems like what I need...I will try it and let you know..

|||

I coded an answer for you:

All you have to do is pass in the interval for the sp_

You can run the #Temp3 first to see what it produces:

-==========================================================

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int
DECLARE @.counter2 int
DECLARE @.Interval int
DECLARE @.BeginRange int
DECLARE @.IntervalCounter int

SET @.Interval = 20
SET @.counter = 1
SET @.BeginRange = @.Interval
SET @.IntervalCounter = @.Interval
SET @.counter2 = 2

WHILE @.counter <> 100

BEGIN
IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1
SET @.IntervalCounter = @.Interval * @.counter2
SET @.counter2 = @.counter2 + 1

END

ELSE
BEGIN
INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1
END
END

Select * from #Temp3
drop table #temp3
-==========================================================

set ANSI_NULLS ON

set QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE [dbo].[sp_AggregateAge](@.Interval int)

AS

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int

DECLARE @.counter2 int

--DECLARE @.Interval int

DECLARE @.BeginRange int

DECLARE @.IntervalCounter int

--SET @.Interval = 20

SET @.counter = 1

SET @.BeginRange = @.Interval

SET @.IntervalCounter = @.Interval

SET @.counter2 = 2

WHILE @.counter <> 100 --This assumes no one is older than 100

BEGIN

IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1

SET @.IntervalCounter = @.Interval * @.counter2

SET @.counter2 = @.counter2 + 1

END

ELSE

BEGIN

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1

END

END

SELECT (t3.BeginRange - @.Interval) AS BeginRange, (t3.BeginRange - 1) AS EndRange, b.Name, SUM(b.TVMins) AS TVMins, SUM(Notional) AS Notional, t3.Age

FROM #Temp3 t3 JOIN Birthday b --JOIN Your Table on Age

ON b.Age = t3.Age

GROUP BY b.Name, t3.Age, t3.BeginRange

ORDER BY t3.BeginRange

DROP TABLE #Temp3

Results:

EXEC sp_AggregateAge 20

BeginRange EndRange Name TVMins Notional Age
-- -- - -- -- --
20 39 Adam 170 10503 35
20 39 John 123 45648 36
40 59 Chris 153 123456 40
40 59 JoAnne 99 65489 53
40 59 Joe 72 5478 42
60 79 Chris 105 4652 69

Adamus

|||

Hi Kenneth,

Thank you very much for your code and it is working fine with the database.

But when I changed your code to dymanic SQL to select the null value of the parameters and check conditions( Like if Provider is not null then ....), It shows a problem.

It is giving error in the grou by line since it cant recognise the '-' character.. it is taking that as a minus operator..

group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Is there any way to split in to get it as range..

The modified code is as follows:

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'select sum(y.TVmins) as TVMinsAmt, sum(y.Notional$) as NotionalAmt, count(*) as Qty, '

SELECT @.sql = @.sql + 'cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + ' + '

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) as AgeGroup '

SELECT @.sql = @.sql + ' from ( select x.TVmins, x.Notional$,x.Age,(x.age - (x.age % @.Interval)) as lowrange,'

SELECT @.sql = @.sql + '(((x.age - (x.age % @.Interval)) + @.Interval) - 1) as highrange'

SELECT @.sql = @.sql + ' from ( select dm.dob, s.TVmins, s.Notional$,'

SELECT @.sql = @.sql + 'cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age'

SELECT @.sql = @.sql + 'from dbo.lkpservice s '

SELECT @.sql = @.sql + 'join dbo.tmpvalidservices_all vs '

SELECT @.sql = @.sql + 'on s.code = vs.service '

SELECT @.sql = @.sql + 'join dbo.tmpdemographics_all dm '

SELECT @.sql = @.sql + 'on dm.rid = vs.rid '

SELECT @.sql = @.sql + 'where s.schedule = @.schedule '

IF @.StartDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete >= coalesce(@.StartDate, vs.complete))'

IF @.EndDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete <= coalesce(@.EndDate, vs.complete))'

IF @.Provider IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.provider = coalesce(@.provider, vs.provider))'

SELECT @.sql = @.sql + ') x'

SELECT @.sql = @.sql + ') y '

SELECT @.sql = @.sql + 'group by cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) '

SELECT @.paramlist = '@.Provider varchar(50),@.Schedule varchar(50),@.StartDate datetime,@.EndDate datetime,@.Interval numeric '

EXEC sp_executesql @.sql,@.paramlist,@.Provider,@.Schedule,@.StartDate,@.EndDate,@.Interval


Thanks

|||

Hi Adamus,

Thanks for your code, Your code is working fine for the database.. But it is taking time to create temp table and I have to deploy this code to the reporting as well..

So I have a doubt whether it is a good idea to create a temp table since it is really a big one which takes a time to execute.

Thank you for your advice and waiting to get your reply...

|||

You don't really need to group by the concatenated age group, I jsut wrote that to show how to create group values like '10-19', '20-29' etc. You can keep the low and high as separate columns instead and perhaps later do the concatenation when presenting the result, if desired.

Try with the below, where you have low and high values as separate columns.
(BTW, is there any special reason you do this as dynamic SQL? For this particular query, it's not necessary. It'll run fine as is, without sp_executesql)

declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

select y.lowrange,
y.highrange,
sum(y.TVmins) as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*) as Qty
from (
select x.TVmins,
x.Notional$,
(x.age - (x.age % @.mod)) as lowrange,
(((x.age - (x.age % @.mod)) + @.mod) - 1) as highrange
from (
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange, y.highrange

=;o)
/Kenneth

Group age by a parameter and find out the value corresponding to that.

Hi guys...

My goal is to change the given stored procedure so that I can find out the different age gorup according to users parameter and find out sumof these values for that group:
s.TVmins, s.Notional$, COUNT(*) AS Qty, SUM(s.TVmins) AS TVMinsAmt, SUM(s.Notional$) AS NotionalAmt
For that I am planning to put another parameter @.count for the group interval and I need to group accordingly.
So my answer should look like:
if the user give the @.count value as 10:
the result should:

age group TVMins Notional

1-9 1560 125632( the sum of that particluar group)
10-19 -- --

91-100 --

I have a field DOB( Date of birth) , I have to extract age from that field first and then group them according to the parameter values and then find its corresponding sums...

<CODE>

--
ALTER PROCEDURE [dbo].[sp_PlanningData]
@.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'SELECT
dm.DOB,
dm.Suburb,
vs.RID,
s.TVmins,
s.Notional$,
COUNT(*) AS Qty,
SUM(s.TVmins) AS TVMinsAmt,
SUM(s.Notional$) AS NotionalAmt

FROM dbo.lkpService s
INNER JOIN dbo.tmpValidServices_ALL vs ON s.Code = vs.Service
INNER JOIN dbo.tmpDemographics_ALL dm ON dm.RID = vs.RID '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpCOC c ON vs.COC = c.pvcode '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpAgency ag ON vs.SiteID = ag.EXACT# '

SELECT @.sql = @.sql + 'WHERE s.Schedule = @.Schedule '

IF @.StartDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete >= @.StartDate ) '

IF @.EndDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete <= @.EndDate ) '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + ' AND (ag.AgencyTypeID = @.ProgrammeID)'

IF @.SiteID IS NOT NULL
SELECT @.sql = @.sql + 'AND (ag.EXACT# = @.SiteID) '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + ' AND (c.pvcode = @.COCGroup OR c.pvcode IN (SELECT COC FROM lkpCOCGroup WHERE COCGroup = @.COCGroup)) '

IF @.Provider IS NOT NULL
SELECT @.sql = @.sql + 'AND (vs.Provider = @.Provider) '

SELECT @.sql = @.sql + 'GROUP dm.Suburb,vs.RID, s.TVmins, s.Notional$ '

SELECT @.paramlist =
' @.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime '

EXEC sp_executesql @.sql,@.paramlist,@.ProgrammeID,@.RegionID,@.SiteID,@.COCGroup,@.Provider,@.Schedule,@.StartDate,@.EndDate

END
-
</CODE>

Hope this will help.. it is really urgent one.. I am trying my best to find it out..
Thanks for your help..

This will give you the range.

Create Table #Temp(Interval int, MyRange varchar(20))

DECLARE @.MyNewInterval int

DECLARE @.MyNewRange varchar(max)

DECLARE @.Interval int

SET @.INTERVAL = 10 --SET YOUR INTERVAL HERE OR PASS IT IN

SET @.MyNewInterval = 0

While @.MyNewInterval < (1000 + @.Interval)

BEGIN

INSERT INTO #Temp(Interval, MyRange) VALUES(@.MyNewInterval, @.MyNewInterval + @.Interval)

SET @.MyNewInterval = @.MyNewInterval + @.INTERVAL

END

SELECT cast(Interval as varchar(50)) + ' - ' + MyRange AS [Range]

FROM #Temp

drop table #temp

UNION your aggregates and you'll have it

Adamus

|||

Hi,

I can create this range, but how can put it into the proc so that I can get the sum values other fields..

Your help is highly appreciation,

|||

UNION your aggregates

Adamus

|||

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

|||

Here's a method that I think can work for you. (it seems to work anyway)
It allows you to use the size of an interval as a parameter, so that you'll group your ages by, say 10-year groups if you pass in '10', and also lets you extract other values that you can sum, count etc...

Assuming you have a dob in the format of ssyymmdd, then this is a way to calculate the current age:

select cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age

(the cast to int is because we need an int later...)

The idea here is to use MOD as the indicator for how the ages should be grouped.
If we say that we set 10 as the range size, then for each age, the lower bound would be:

age - (age % 10)

and the higher bound would be:

age - (age % 10) + 10

To start, then, you could select the values you want to sum, along with the calculated age.

select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test

Use this is a derived table and find out the low and high ranges for the selected grouping:

declare @.mod int
set @.mod = 10

select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x

Now we can wrap this into yet another derived table and do the final grouping and sum up the values for each group.
It's not entirely necessary to wrap further out, but it keeps the code a bit more readable, since we can group by name instead of repeating the algorithms for low and high..
So the final construct should look something like this;

declare @.mod int
set @.mod = 10

select y.lowrange,
y.highrange,
sum(y.val1) as val1Sum,
sum(y.val2) as val2Sum,
count(*)
from (
select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange

To change the size of the groups, just set @.mod to the desired range, 5, 8, 10, 20 or whatever.

Hope it helps you some.

=;o)
/Kenneth

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

I will give you the answer tomorrow.

Adamus

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

1. Add the one field "Range" in #temp table to your existing table with null values. (allow nulls)
2. Add all fields from your existing table to the #temp table with null values. (allow nulls)

Now you have the same fields in both tables. This is key.

3. Now create your #temp table with only the ranges and populate.
4. UNION ALL your aggregate query.
4b. In your aggregeate query, you'll have to determine which row the aggregate hypothetically will go.
5. You should now have your desired results.

Does this makes sense?

Adamus

|||

Hi Adamus,

I understand what you said. But not sure whether its a good idea to add a new field to the table in my case,

As I added in the first message, I am taking values from different tables and I am unable to add a field to any of the tables due to some security reasons.

Can I add your query into my query or DO the union all ?

I cant resolve this..I am really confused now..

|||

I couldn't quite follow all the twist and turns in the dynamic SQL stuff (not sure that the literal example is actually runnable?), but from what I gathered about the need to produce the age groupings and the two sums and count, I belive that this is about what you need to get those particular items...

You may try and see if it runs on your system.

select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))

Assuming that the above 'base query' is ok for the purpose, the below would (hopefully) group by the age-interval given and sum up the two values according to each group. You may need to declare additional variables @.startdate, @.enddate and @.provider though. The age-intervals returned will be only those where there are ages found in the data, there will be no empty intervals. If that is a requirement (and assuming the whole shebang actually is useful =;o), it's possible to generate empty groups with counts of zero, though that is a bit more code, and also requires a numberstable.
Another assumption is also that DOB is in the format of 'SSYYMMDD'

Anyway, try and see if the below is of any use to you.

-- with ranges contained in data (no empty intervals)
declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

selectcast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))as AgeGroup,
sum(y.TVmins)as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*)as Qty
from(
select x.TVmins,
x.Notional$,
(x.age -(x.age % @.mod))as lowrange,
(((x.age -(x.age % @.mod))+ @.mod)- 1)as highrange
from(
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))
) x
) y
groupbycast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))
orderbycast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))

Hope it works out for you =;o)

=;o)
/Kenneth

|||

Hi Kenneth,

Thank you very much for your help.

It seems like what I need...I will try it and let you know..

|||

I coded an answer for you:

All you have to do is pass in the interval for the sp_

You can run the #Temp3 first to see what it produces:

-==========================================================

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int
DECLARE @.counter2 int
DECLARE @.Interval int
DECLARE @.BeginRange int
DECLARE @.IntervalCounter int

SET @.Interval = 20
SET @.counter = 1
SET @.BeginRange = @.Interval
SET @.IntervalCounter = @.Interval
SET @.counter2 = 2

WHILE @.counter <> 100

BEGIN
IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1
SET @.IntervalCounter = @.Interval * @.counter2
SET @.counter2 = @.counter2 + 1

END

ELSE
BEGIN
INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1
END
END

Select * from #Temp3
drop table #temp3
-==========================================================

set ANSI_NULLS ON

set QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE [dbo].[sp_AggregateAge](@.Interval int)

AS

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int

DECLARE @.counter2 int

--DECLARE @.Interval int

DECLARE @.BeginRange int

DECLARE @.IntervalCounter int

--SET @.Interval = 20

SET @.counter = 1

SET @.BeginRange = @.Interval

SET @.IntervalCounter = @.Interval

SET @.counter2 = 2

WHILE @.counter <> 100 --This assumes no one is older than 100

BEGIN

IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1

SET @.IntervalCounter = @.Interval * @.counter2

SET @.counter2 = @.counter2 + 1

END

ELSE

BEGIN

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1

END

END

SELECT (t3.BeginRange - @.Interval) AS BeginRange, (t3.BeginRange - 1) AS EndRange, b.Name, SUM(b.TVMins) AS TVMins, SUM(Notional) AS Notional, t3.Age

FROM #Temp3 t3 JOIN Birthday b --JOIN Your Table on Age

ON b.Age = t3.Age

GROUP BY b.Name, t3.Age, t3.BeginRange

ORDER BY t3.BeginRange

DROP TABLE #Temp3

Results:

EXEC sp_AggregateAge 20

BeginRange EndRange Name TVMins Notional Age
-- -- - -- -- --
20 39 Adam 170 10503 35
20 39 John 123 45648 36
40 59 Chris 153 123456 40
40 59 JoAnne 99 65489 53
40 59 Joe 72 5478 42
60 79 Chris 105 4652 69

Adamus

|||

Hi Kenneth,

Thank you very much for your code and it is working fine with the database.

But when I changed your code to dymanic SQL to select the null value of the parameters and check conditions( Like if Provider is not null then ....), It shows a problem.

It is giving error in the grou by line since it cant recognise the '-' character.. it is taking that as a minus operator..

group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Is there any way to split in to get it as range..

The modified code is as follows:

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'select sum(y.TVmins) as TVMinsAmt, sum(y.Notional$) as NotionalAmt, count(*) as Qty, '

SELECT @.sql = @.sql + 'cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + ' + '

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) as AgeGroup '

SELECT @.sql = @.sql + ' from ( select x.TVmins, x.Notional$,x.Age,(x.age - (x.age % @.Interval)) as lowrange,'

SELECT @.sql = @.sql + '(((x.age - (x.age % @.Interval)) + @.Interval) - 1) as highrange'

SELECT @.sql = @.sql + ' from ( select dm.dob, s.TVmins, s.Notional$,'

SELECT @.sql = @.sql + 'cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age'

SELECT @.sql = @.sql + 'from dbo.lkpservice s '

SELECT @.sql = @.sql + 'join dbo.tmpvalidservices_all vs '

SELECT @.sql = @.sql + 'on s.code = vs.service '

SELECT @.sql = @.sql + 'join dbo.tmpdemographics_all dm '

SELECT @.sql = @.sql + 'on dm.rid = vs.rid '

SELECT @.sql = @.sql + 'where s.schedule = @.schedule '

IF @.StartDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete >= coalesce(@.StartDate, vs.complete))'

IF @.EndDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete <= coalesce(@.EndDate, vs.complete))'

IF @.Provider IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.provider = coalesce(@.provider, vs.provider))'

SELECT @.sql = @.sql + ') x'

SELECT @.sql = @.sql + ') y '

SELECT @.sql = @.sql + 'group by cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) '

SELECT @.paramlist = '@.Provider varchar(50),@.Schedule varchar(50),@.StartDate datetime,@.EndDate datetime,@.Interval numeric '

EXEC sp_executesql @.sql,@.paramlist,@.Provider,@.Schedule,@.StartDate,@.EndDate,@.Interval


Thanks

|||

Hi Adamus,

Thanks for your code, Your code is working fine for the database.. But it is taking time to create temp table and I have to deploy this code to the reporting as well..

So I have a doubt whether it is a good idea to create a temp table since it is really a big one which takes a time to execute.

Thank you for your advice and waiting to get your reply...

|||

You don't really need to group by the concatenated age group, I jsut wrote that to show how to create group values like '10-19', '20-29' etc. You can keep the low and high as separate columns instead and perhaps later do the concatenation when presenting the result, if desired.

Try with the below, where you have low and high values as separate columns.
(BTW, is there any special reason you do this as dynamic SQL? For this particular query, it's not necessary. It'll run fine as is, without sp_executesql)

declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

selecty.lowrange,
y.highrange,
sum(y.TVmins)as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*)as Qty
from(
select x.TVmins,
x.Notional$,
(x.age -(x.age % @.mod))as lowrange,
(((x.age -(x.age % @.mod))+ @.mod)- 1)as highrange
from(
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))
) x
) y
groupbyy.lowrange, y.highrange
orderbyy.lowrange, y.highrange

=;o)
/Kenneth

Group age by a parameter and find out the value corresponding to that.

Hi guys...

My goal is to change the given stored procedure so that I can find out the different age gorup according to users parameter and find out sumof these values for that group:
s.TVmins, s.Notional$, COUNT(*) AS Qty, SUM(s.TVmins) AS TVMinsAmt, SUM(s.Notional$) AS NotionalAmt
For that I am planning to put another parameter @.count for the group interval and I need to group accordingly.
So my answer should look like:
if the user give the @.count value as 10:
the result should:

age group TVMins Notional

1-9 1560 125632( the sum of that particluar group)
10-19 -- --

91-100 --

I have a field DOB( Date of birth) , I have to extract age from that field first and then group them according to the parameter values and then find its corresponding sums...

<CODE>

--
ALTER PROCEDURE [dbo].[sp_PlanningData]
@.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'SELECT
dm.DOB,
dm.Suburb,
vs.RID,
s.TVmins,
s.Notional$,
COUNT(*) AS Qty,
SUM(s.TVmins) AS TVMinsAmt,
SUM(s.Notional$) AS NotionalAmt

FROM dbo.lkpService s
INNER JOIN dbo.tmpValidServices_ALL vs ON s.Code = vs.Service
INNER JOIN dbo.tmpDemographics_ALL dm ON dm.RID = vs.RID '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpCOC c ON vs.COC = c.pvcode '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpAgency ag ON vs.SiteID = ag.EXACT# '

SELECT @.sql = @.sql + 'WHERE s.Schedule = @.Schedule '

IF @.StartDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete >= @.StartDate ) '

IF @.EndDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete <= @.EndDate ) '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + ' AND (ag.AgencyTypeID = @.ProgrammeID)'

IF @.SiteID IS NOT NULL
SELECT @.sql = @.sql + 'AND (ag.EXACT# = @.SiteID) '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + ' AND (c.pvcode = @.COCGroup OR c.pvcode IN (SELECT COC FROM lkpCOCGroup WHERE COCGroup = @.COCGroup)) '

IF @.Provider IS NOT NULL
SELECT @.sql = @.sql + 'AND (vs.Provider = @.Provider) '

SELECT @.sql = @.sql + 'GROUP dm.Suburb,vs.RID, s.TVmins, s.Notional$ '

SELECT @.paramlist =
' @.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime '

EXEC sp_executesql @.sql,@.paramlist,@.ProgrammeID,@.RegionID,@.SiteID,@.COCGroup,@.Provider,@.Schedule,@.StartDate,@.EndDate

END
-
</CODE>

Hope this will help.. it is really urgent one.. I am trying my best to find it out..
Thanks for your help..

This will give you the range.

Create Table #Temp(Interval int, MyRange varchar(20))

DECLARE @.MyNewInterval int

DECLARE @.MyNewRange varchar(max)

DECLARE @.Interval int

SET @.INTERVAL = 10 --SET YOUR INTERVAL HERE OR PASS IT IN

SET @.MyNewInterval = 0

While @.MyNewInterval < (1000 + @.Interval)

BEGIN

INSERT INTO #Temp(Interval, MyRange) VALUES(@.MyNewInterval, @.MyNewInterval + @.Interval)

SET @.MyNewInterval = @.MyNewInterval + @.INTERVAL

END

SELECT cast(Interval as varchar(50)) + ' - ' + MyRange AS [Range]

FROM #Temp

drop table #temp

UNION your aggregates and you'll have it

Adamus

|||

Hi,

I can create this range, but how can put it into the proc so that I can get the sum values other fields..

Your help is highly appreciation,

|||

UNION your aggregates

Adamus

|||

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

|||

Here's a method that I think can work for you. (it seems to work anyway)
It allows you to use the size of an interval as a parameter, so that you'll group your ages by, say 10-year groups if you pass in '10', and also lets you extract other values that you can sum, count etc...

Assuming you have a dob in the format of ssyymmdd, then this is a way to calculate the current age:

select cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age

(the cast to int is because we need an int later...)

The idea here is to use MOD as the indicator for how the ages should be grouped.
If we say that we set 10 as the range size, then for each age, the lower bound would be:

age - (age % 10)

and the higher bound would be:

age - (age % 10) + 10

To start, then, you could select the values you want to sum, along with the calculated age.

select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test

Use this is a derived table and find out the low and high ranges for the selected grouping:

declare @.mod int
set @.mod = 10

select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x

Now we can wrap this into yet another derived table and do the final grouping and sum up the values for each group.
It's not entirely necessary to wrap further out, but it keeps the code a bit more readable, since we can group by name instead of repeating the algorithms for low and high..
So the final construct should look something like this;

declare @.mod int
set @.mod = 10

select y.lowrange,
y.highrange,
sum(y.val1) as val1Sum,
sum(y.val2) as val2Sum,
count(*)
from (
select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange

To change the size of the groups, just set @.mod to the desired range, 5, 8, 10, 20 or whatever.

Hope it helps you some.

=;o)
/Kenneth

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

I will give you the answer tomorrow.

Adamus

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

1. Add the one field "Range" in #temp table to your existing table with null values. (allow nulls)
2. Add all fields from your existing table to the #temp table with null values. (allow nulls)

Now you have the same fields in both tables. This is key.

3. Now create your #temp table with only the ranges and populate.
4. UNION ALL your aggregate query.
4b. In your aggregeate query, you'll have to determine which row the aggregate hypothetically will go.
5. You should now have your desired results.

Does this makes sense?

Adamus

|||

Hi Adamus,

I understand what you said. But not sure whether its a good idea to add a new field to the table in my case,

As I added in the first message, I am taking values from different tables and I am unable to add a field to any of the tables due to some security reasons.

Can I add your query into my query or DO the union all ?

I cant resolve this..I am really confused now..

|||

I couldn't quite follow all the twist and turns in the dynamic SQL stuff (not sure that the literal example is actually runnable?), but from what I gathered about the need to produce the age groupings and the two sums and count, I belive that this is about what you need to get those particular items...

You may try and see if it runs on your system.

select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))

Assuming that the above 'base query' is ok for the purpose, the below would (hopefully) group by the age-interval given and sum up the two values according to each group. You may need to declare additional variables @.startdate, @.enddate and @.provider though. The age-intervals returned will be only those where there are ages found in the data, there will be no empty intervals. If that is a requirement (and assuming the whole shebang actually is useful =;o), it's possible to generate empty groups with counts of zero, though that is a bit more code, and also requires a numberstable.
Another assumption is also that DOB is in the format of 'SSYYMMDD'

Anyway, try and see if the below is of any use to you.

-- with ranges contained in data (no empty intervals)
declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

selectcast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))as AgeGroup,
sum(y.TVmins)as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*)as Qty
from(
select x.TVmins,
x.Notional$,
(x.age -(x.age % @.mod))as lowrange,
(((x.age -(x.age % @.mod))+ @.mod)- 1)as highrange
from(
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))
) x
) y
groupbycast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))
orderbycast(y.lowrange asvarchar(10))+'-'+cast(y.highrange asvarchar(10))

Hope it works out for you =;o)

=;o)
/Kenneth

|||

Hi Kenneth,

Thank you very much for your help.

It seems like what I need...I will try it and let you know..

|||

I coded an answer for you:

All you have to do is pass in the interval for the sp_

You can run the #Temp3 first to see what it produces:

-==========================================================

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int
DECLARE @.counter2 int
DECLARE @.Interval int
DECLARE @.BeginRange int
DECLARE @.IntervalCounter int

SET @.Interval = 20
SET @.counter = 1
SET @.BeginRange = @.Interval
SET @.IntervalCounter = @.Interval
SET @.counter2 = 2

WHILE @.counter <> 100

BEGIN
IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1
SET @.IntervalCounter = @.Interval * @.counter2
SET @.counter2 = @.counter2 + 1

END

ELSE
BEGIN
INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1
END
END

Select * from #Temp3
drop table #temp3
-==========================================================

set ANSI_NULLS ON

set QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE [dbo].[sp_AggregateAge](@.Interval int)

AS

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int

DECLARE @.counter2 int

--DECLARE @.Interval int

DECLARE @.BeginRange int

DECLARE @.IntervalCounter int

--SET @.Interval = 20

SET @.counter = 1

SET @.BeginRange = @.Interval

SET @.IntervalCounter = @.Interval

SET @.counter2 = 2

WHILE @.counter <> 100 --This assumes no one is older than 100

BEGIN

IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1

SET @.IntervalCounter = @.Interval * @.counter2

SET @.counter2 = @.counter2 + 1

END

ELSE

BEGIN

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1

END

END

SELECT (t3.BeginRange - @.Interval) AS BeginRange, (t3.BeginRange - 1) AS EndRange, b.Name, SUM(b.TVMins) AS TVMins, SUM(Notional) AS Notional, t3.Age

FROM #Temp3 t3 JOIN Birthday b --JOIN Your Table on Age

ON b.Age = t3.Age

GROUP BY b.Name, t3.Age, t3.BeginRange

ORDER BY t3.BeginRange

DROP TABLE #Temp3

Results:

EXEC sp_AggregateAge 20

BeginRange EndRange Name TVMins Notional Age
-- -- - -- -- --
20 39 Adam 170 10503 35
20 39 John 123 45648 36
40 59 Chris 153 123456 40
40 59 JoAnne 99 65489 53
40 59 Joe 72 5478 42
60 79 Chris 105 4652 69

Adamus

|||

Hi Kenneth,

Thank you very much for your code and it is working fine with the database.

But when I changed your code to dymanic SQL to select the null value of the parameters and check conditions( Like if Provider is not null then ....), It shows a problem.

It is giving error in the grou by line since it cant recognise the '-' character.. it is taking that as a minus operator..

group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Is there any way to split in to get it as range..

The modified code is as follows:

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'select sum(y.TVmins) as TVMinsAmt, sum(y.Notional$) as NotionalAmt, count(*) as Qty, '

SELECT @.sql = @.sql + 'cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + ' + '

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) as AgeGroup '

SELECT @.sql = @.sql + ' from ( select x.TVmins, x.Notional$,x.Age,(x.age - (x.age % @.Interval)) as lowrange,'

SELECT @.sql = @.sql + '(((x.age - (x.age % @.Interval)) + @.Interval) - 1) as highrange'

SELECT @.sql = @.sql + ' from ( select dm.dob, s.TVmins, s.Notional$,'

SELECT @.sql = @.sql + 'cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age'

SELECT @.sql = @.sql + 'from dbo.lkpservice s '

SELECT @.sql = @.sql + 'join dbo.tmpvalidservices_all vs '

SELECT @.sql = @.sql + 'on s.code = vs.service '

SELECT @.sql = @.sql + 'join dbo.tmpdemographics_all dm '

SELECT @.sql = @.sql + 'on dm.rid = vs.rid '

SELECT @.sql = @.sql + 'where s.schedule = @.schedule '

IF @.StartDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete >= coalesce(@.StartDate, vs.complete))'

IF @.EndDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete <= coalesce(@.EndDate, vs.complete))'

IF @.Provider IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.provider = coalesce(@.provider, vs.provider))'

SELECT @.sql = @.sql + ') x'

SELECT @.sql = @.sql + ') y '

SELECT @.sql = @.sql + 'group by cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) '

SELECT @.paramlist = '@.Provider varchar(50),@.Schedule varchar(50),@.StartDate datetime,@.EndDate datetime,@.Interval numeric '

EXEC sp_executesql @.sql,@.paramlist,@.Provider,@.Schedule,@.StartDate,@.EndDate,@.Interval


Thanks

|||

Hi Adamus,

Thanks for your code, Your code is working fine for the database.. But it is taking time to create temp table and I have to deploy this code to the reporting as well..

So I have a doubt whether it is a good idea to create a temp table since it is really a big one which takes a time to execute.

Thank you for your advice and waiting to get your reply...

|||

You don't really need to group by the concatenated age group, I jsut wrote that to show how to create group values like '10-19', '20-29' etc. You can keep the low and high as separate columns instead and perhaps later do the concatenation when presenting the result, if desired.

Try with the below, where you have low and high values as separate columns.
(BTW, is there any special reason you do this as dynamic SQL? For this particular query, it's not necessary. It'll run fine as is, without sp_executesql)

declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

selecty.lowrange,
y.highrange,
sum(y.TVmins)as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*)as Qty
from(
select x.TVmins,
x.Notional$,
(x.age -(x.age % @.mod))as lowrange,
(((x.age -(x.age % @.mod))+ @.mod)- 1)as highrange
from(
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob,getdate())/ 365.25)asint)as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and(vs.complete >=coalesce(@.startdate, vs.complete))
and(vs.complete <=coalesce(@.enddate, vs.complete))
and(vs.provider =coalesce(@.provider, vs.provider))
) x
) y
groupbyy.lowrange, y.highrange
orderbyy.lowrange, y.highrange

=;o)
/Kenneth

Group age by a parameter and find out the value corresponding to that.

Hi guys...

My goal is to change the given stored procedure so that I can find out the different age gorup according to users parameter and find out sumof these values for that group:
s.TVmins, s.Notional$, COUNT(*) AS Qty, SUM(s.TVmins) AS TVMinsAmt, SUM(s.Notional$) AS NotionalAmt
For that I am planning to put another parameter @.count for the group interval and I need to group accordingly.
So my answer should look like:
if the user give the @.count value as 10:
the result should:

age group TVMins Notional

1-9 1560 125632( the sum of that particluar group)
10-19 -- --

91-100 --

I have a field DOB( Date of birth) , I have to extract age from that field first and then group them according to the parameter values and then find its corresponding sums...

<CODE>

--
ALTER PROCEDURE [dbo].[sp_PlanningData]
@.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'SELECT
dm.DOB,
dm.Suburb,
vs.RID,
s.TVmins,
s.Notional$,
COUNT(*) AS Qty,
SUM(s.TVmins) AS TVMinsAmt,
SUM(s.Notional$) AS NotionalAmt

FROM dbo.lkpService s
INNER JOIN dbo.tmpValidServices_ALL vs ON s.Code = vs.Service
INNER JOIN dbo.tmpDemographics_ALL dm ON dm.RID = vs.RID '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpCOC c ON vs.COC = c.pvcode '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + 'LEFT OUTER JOIN dbo.lkpAgency ag ON vs.SiteID = ag.EXACT# '

SELECT @.sql = @.sql + 'WHERE s.Schedule = @.Schedule '

IF @.StartDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete >= @.StartDate ) '

IF @.EndDate IS NOT NULL
SELECT @.sql = @.sql + ' AND (vs.Complete <= @.EndDate ) '

IF @.ProgrammeID IS NOT NULL
SELECT @.sql = @.sql + ' AND (ag.AgencyTypeID = @.ProgrammeID)'

IF @.SiteID IS NOT NULL
SELECT @.sql = @.sql + 'AND (ag.EXACT# = @.SiteID) '

IF @.COCGroup IS NOT NULL
SELECT @.sql = @.sql + ' AND (c.pvcode = @.COCGroup OR c.pvcode IN (SELECT COC FROM lkpCOCGroup WHERE COCGroup = @.COCGroup)) '

IF @.Provider IS NOT NULL
SELECT @.sql = @.sql + 'AND (vs.Provider = @.Provider) '

SELECT @.sql = @.sql + 'GROUP dm.Suburb,vs.RID, s.TVmins, s.Notional$ '

SELECT @.paramlist =
' @.ProgrammeID numeric,
@.RegionID numeric,
@.SiteID numeric,
@.COCGroup varchar(50),
@.Provider varchar(50),
@.Schedule varchar(50),
@.StartDate datetime,
@.EndDate datetime '

EXEC sp_executesql @.sql,@.paramlist,@.ProgrammeID,@.RegionID,@.SiteID,@.COCGroup,@.Provider,@.Schedule,@.StartDate,@.EndDate

END
-
</CODE>

Hope this will help.. it is really urgent one.. I am trying my best to find it out..
Thanks for your help..

This will give you the range.

Create Table #Temp(Interval int, MyRange varchar(20))

DECLARE @.MyNewInterval int

DECLARE @.MyNewRange varchar(max)

DECLARE @.Interval int

SET @.INTERVAL = 10 --SET YOUR INTERVAL HERE OR PASS IT IN

SET @.MyNewInterval = 0

While @.MyNewInterval < (1000 + @.Interval)

BEGIN

INSERT INTO #Temp(Interval, MyRange) VALUES(@.MyNewInterval, @.MyNewInterval + @.Interval)

SET @.MyNewInterval = @.MyNewInterval + @.INTERVAL

END

SELECT cast(Interval as varchar(50)) + ' - ' + MyRange AS [Range]

FROM #Temp

drop table #temp

UNION your aggregates and you'll have it

Adamus

|||

Hi,

I can create this range, but how can put it into the proc so that I can get the sum values other fields..

Your help is highly appreciation,

|||

UNION your aggregates

Adamus

|||

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

|||

Here's a method that I think can work for you. (it seems to work anyway)
It allows you to use the size of an interval as a parameter, so that you'll group your ages by, say 10-year groups if you pass in '10', and also lets you extract other values that you can sum, count etc...

Assuming you have a dob in the format of ssyymmdd, then this is a way to calculate the current age:

select cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age

(the cast to int is because we need an int later...)

The idea here is to use MOD as the indicator for how the ages should be grouped.
If we say that we set 10 as the range size, then for each age, the lower bound would be:

age - (age % 10)

and the higher bound would be:

age - (age % 10) + 10

To start, then, you could select the values you want to sum, along with the calculated age.

select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test

Use this is a derived table and find out the low and high ranges for the selected grouping:

declare @.mod int
set @.mod = 10

select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x

Now we can wrap this into yet another derived table and do the final grouping and sum up the values for each group.
It's not entirely necessary to wrap further out, but it keeps the code a bit more readable, since we can group by name instead of repeating the algorithms for low and high..
So the final construct should look something like this;

declare @.mod int
set @.mod = 10

select y.lowrange,
y.highrange,
sum(y.val1) as val1Sum,
sum(y.val2) as val2Sum,
count(*)
from (
select x.val1,
x.val2,
x.age - (x.age % @.mod) as lowrange,
(x.age - (x.age % @.mod)) + @.mod as highrange
from (
select dob,
val1,
val2,
cast(ceiling(datediff(day, dob, getdate()) / 365.25) as int) as age
from test
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange

To change the size of the groups, just set @.mod to the desired range, 5, 8, 10, 20 or whatever.

Hope it helps you some.

=;o)
/Kenneth

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

I will give you the answer tomorrow.

Adamus

|||

Bisjom wrote:

Hi,

I could not get u, How can I do that.. could you explain a bit more please..

1. Add the one field "Range" in #temp table to your existing table with null values. (allow nulls)
2. Add all fields from your existing table to the #temp table with null values. (allow nulls)

Now you have the same fields in both tables. This is key.

3. Now create your #temp table with only the ranges and populate.
4. UNION ALL your aggregate query.
4b. In your aggregeate query, you'll have to determine which row the aggregate hypothetically will go.
5. You should now have your desired results.

Does this makes sense?

Adamus

|||

Hi Adamus,

I understand what you said. But not sure whether its a good idea to add a new field to the table in my case,

As I added in the first message, I am taking values from different tables and I am unable to add a field to any of the tables due to some security reasons.

Can I add your query into my query or DO the union all ?

I cant resolve this..I am really confused now..

|||

I couldn't quite follow all the twist and turns in the dynamic SQL stuff (not sure that the literal example is actually runnable?), but from what I gathered about the need to produce the age groupings and the two sums and count, I belive that this is about what you need to get those particular items...

You may try and see if it runs on your system.

select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))

Assuming that the above 'base query' is ok for the purpose, the below would (hopefully) group by the age-interval given and sum up the two values according to each group. You may need to declare additional variables @.startdate, @.enddate and @.provider though. The age-intervals returned will be only those where there are ages found in the data, there will be no empty intervals. If that is a requirement (and assuming the whole shebang actually is useful =;o), it's possible to generate empty groups with counts of zero, though that is a bit more code, and also requires a numberstable.
Another assumption is also that DOB is in the format of 'SSYYMMDD'

Anyway, try and see if the below is of any use to you.

-- with ranges contained in data (no empty intervals)
declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

select cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10)) as AgeGroup,
sum(y.TVmins) as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*) as Qty
from (
select x.TVmins,
x.Notional$,
(x.age - (x.age % @.mod)) as lowrange,
(((x.age - (x.age % @.mod)) + @.mod) - 1) as highrange
from (
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))
) x
) y
group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))
order by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Hope it works out for you =;o)

=;o)
/Kenneth

|||

Hi Kenneth,

Thank you very much for your help.

It seems like what I need...I will try it and let you know..

|||

I coded an answer for you:

All you have to do is pass in the interval for the sp_

You can run the #Temp3 first to see what it produces:

-==========================================================

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int
DECLARE @.counter2 int
DECLARE @.Interval int
DECLARE @.BeginRange int
DECLARE @.IntervalCounter int

SET @.Interval = 20
SET @.counter = 1
SET @.BeginRange = @.Interval
SET @.IntervalCounter = @.Interval
SET @.counter2 = 2

WHILE @.counter <> 100

BEGIN
IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1
SET @.IntervalCounter = @.Interval * @.counter2
SET @.counter2 = @.counter2 + 1

END

ELSE
BEGIN
INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1
END
END

Select * from #Temp3
drop table #temp3
-==========================================================

set ANSI_NULLS ON

set QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE [dbo].[sp_AggregateAge](@.Interval int)

AS

CREATE TABLE #Temp3(Age int, BeginRange bigint)

DECLARE @.counter int

DECLARE @.counter2 int

--DECLARE @.Interval int

DECLARE @.BeginRange int

DECLARE @.IntervalCounter int

--SET @.Interval = 20

SET @.counter = 1

SET @.BeginRange = @.Interval

SET @.IntervalCounter = @.Interval

SET @.counter2 = 2

WHILE @.counter <> 100 --This assumes no one is older than 100

BEGIN

IF @.Counter % @.Interval = 0

BEGIN

SET @.BeginRange = @.BeginRange + @.Interval

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.BeginRange)

SET @.counter = @.counter + 1

SET @.IntervalCounter = @.Interval * @.counter2

SET @.counter2 = @.counter2 + 1

END

ELSE

BEGIN

INSERT INTO #Temp3(Age, BeginRange)VALUES(@.Counter, @.IntervalCounter)

SET @.counter = @.counter + 1

END

END

SELECT (t3.BeginRange - @.Interval) AS BeginRange, (t3.BeginRange - 1) AS EndRange, b.Name, SUM(b.TVMins) AS TVMins, SUM(Notional) AS Notional, t3.Age

FROM #Temp3 t3 JOIN Birthday b --JOIN Your Table on Age

ON b.Age = t3.Age

GROUP BY b.Name, t3.Age, t3.BeginRange

ORDER BY t3.BeginRange

DROP TABLE #Temp3

Results:

EXEC sp_AggregateAge 20

BeginRange EndRange Name TVMins Notional Age
-- -- - -- -- --
20 39 Adam 170 10503 35
20 39 John 123 45648 36
40 59 Chris 153 123456 40
40 59 JoAnne 99 65489 53
40 59 Joe 72 5478 42
60 79 Chris 105 4652 69

Adamus

|||

Hi Kenneth,

Thank you very much for your code and it is working fine with the database.

But when I changed your code to dymanic SQL to select the null value of the parameters and check conditions( Like if Provider is not null then ....), It shows a problem.

It is giving error in the grou by line since it cant recognise the '-' character.. it is taking that as a minus operator..

group by cast(y.lowrange as varchar(10)) + '-' + cast(y.highrange as varchar(10))

Is there any way to split in to get it as range..

The modified code is as follows:

DECLARE
@.sql nvarchar(4000),
@.paramlist nvarchar(4000)

SELECT @.sql = 'select sum(y.TVmins) as TVMinsAmt, sum(y.Notional$) as NotionalAmt, count(*) as Qty, '

SELECT @.sql = @.sql + 'cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + ' + '

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) as AgeGroup '

SELECT @.sql = @.sql + ' from ( select x.TVmins, x.Notional$,x.Age,(x.age - (x.age % @.Interval)) as lowrange,'

SELECT @.sql = @.sql + '(((x.age - (x.age % @.Interval)) + @.Interval) - 1) as highrange'

SELECT @.sql = @.sql + ' from ( select dm.dob, s.TVmins, s.Notional$,'

SELECT @.sql = @.sql + 'cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age'

SELECT @.sql = @.sql + 'from dbo.lkpservice s '

SELECT @.sql = @.sql + 'join dbo.tmpvalidservices_all vs '

SELECT @.sql = @.sql + 'on s.code = vs.service '

SELECT @.sql = @.sql + 'join dbo.tmpdemographics_all dm '

SELECT @.sql = @.sql + 'on dm.rid = vs.rid '

SELECT @.sql = @.sql + 'where s.schedule = @.schedule '

IF @.StartDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete >= coalesce(@.StartDate, vs.complete))'

IF @.EndDate IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.complete <= coalesce(@.EndDate, vs.complete))'

IF @.Provider IS NOT NULL

SELECT @.sql = @.sql + 'and (vs.provider = coalesce(@.provider, vs.provider))'

SELECT @.sql = @.sql + ') x'

SELECT @.sql = @.sql + ') y '

SELECT @.sql = @.sql + 'group by cast(y.lowrange as varchar(10)) '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' '

SELECT @.sql = @.sql + '+'

SELECT @.sql = @.sql + ' cast(y.highrange as varchar(10)) '

SELECT @.paramlist = '@.Provider varchar(50),@.Schedule varchar(50),@.StartDate datetime,@.EndDate datetime,@.Interval numeric '

EXEC sp_executesql @.sql,@.paramlist,@.Provider,@.Schedule,@.StartDate,@.EndDate,@.Interval


Thanks

|||

Hi Adamus,

Thanks for your code, Your code is working fine for the database.. But it is taking time to create temp table and I have to deploy this code to the reporting as well..

So I have a doubt whether it is a good idea to create a temp table since it is really a big one which takes a time to execute.

Thank you for your advice and waiting to get your reply...

|||

You don't really need to group by the concatenated age group, I jsut wrote that to show how to create group values like '10-19', '20-29' etc. You can keep the low and high as separate columns instead and perhaps later do the concatenation when presenting the result, if desired.

Try with the below, where you have low and high values as separate columns.
(BTW, is there any special reason you do this as dynamic SQL? For this particular query, it's not necessary. It'll run fine as is, without sp_executesql)

declare @.mod int
set @.mod = 10 -- set to change the range of low/high groupings

select y.lowrange,
y.highrange,
sum(y.TVmins) as TVMinsAmt,
sum(y.Notional$) as NotionalAmt,
count(*) as Qty
from (
select x.TVmins,
x.Notional$,
(x.age - (x.age % @.mod)) as lowrange,
(((x.age - (x.age % @.mod)) + @.mod) - 1) as highrange
from (
select dm.dob,
s.TVmins,
s.Notional$,
cast(ceiling(datediff(day, dm.dob, getdate()) / 365.25) as int) as age
from dbo.lkpservice s
join dbo.tmpvalidservices_all vs
on s.code = vs.service
join dbo.tmpdemographics_all dm
on dm.rid = vs.rid
where s.schedule = @.schedule
and (vs.complete >= coalesce(@.startdate, vs.complete))
and (vs.complete <= coalesce(@.enddate, vs.complete))
and (vs.provider = coalesce(@.provider, vs.provider))
) x
) y
group by y.lowrange, y.highrange
order by y.lowrange, y.highrange

=;o)
/Kenneth