Showing posts with label parameter. Show all posts
Showing posts with label parameter. Show all posts

Wednesday, March 28, 2012

Grouping parameter value

I'm working on a stored procedure that works fine. I just want to make it possible for the user to be able to have a drop down list in reporting services to display the "question codes" grouped by whatever the first two digits are. for example.

VT01

VT02

VT03

VN01

VN02

VN03

ST01

ST02

ST03

instead of listing everything, i want the viewers to see this

VT

VN

ST

or an alias for each of these like this:

Vet Tasks

Vet National

Survey Tasks

Survey National

any ideas, here's my current code, which is pullin up anything with the added substring part

Code Snippet

ALTER PROCEDURE [dbo].[Testing_Questions]

(@.Region_Key int=null,@.QuestionCode char(5))

AS

BEGIN

SELECT dbo.Qry_Questions.Territory,

dbo.Qry_Questions.SalesResponsible,

dbo.Qry_Questions.Customer,

dbo.Qry_Questions.Date,

dbo.Qry_Questions.StoreName,

dbo.Qry_Questions.PostCode,

dbo.Qry_Questions.Address2,

dbo.Qry_Questions.[Question Code],

dbo.Qry_Questions.Question,

dbo.Qry_Questions.[Response Type],

dbo.Qry_Questions.response,

dbo.Qry_Questions.sales_person_code,

dbo.Qry_Sales_Group.Region_Key,

dbo.Qry_Sales_Group.Region

FROM dbo.Qry_Questions

INNER JOIN dbo.Qry_Sales_Group

ON dbo.Qry_Questions.sales_person_code COLLATE SQL_Latin1_General_CP1_CI_AS = dbo.Qry_Sales_Group.SalesPerson_Purchaser_Code

WHERE REGION_KEY=@.Region_Key

AND SUBSTRING(dbo.Qry_Questions.[Question Code],0,3)=@.QuestionCode

END

SET NOCOUNT OFF

You might try using the follwing as the grouping expression:

Code Snippet

=Left(Fields!<your_field>.Value, 2)

From there you could either set up a CASE statement or code for your aliases.

Hope this helps!

Scott

|||

I have the report working, i just want to be able to group the choices into 6 different choices. I know there is a way to do this in the report parameters properties box. I created my own non queried values that look like this:

Label Value

Survey national =IIF(Left(Fields!Question_Code.Value, 2)="SN",Fields!Question_Code.Value,nothing)

Survey vet =IIF(Left(Fields!Question_Code.Value, 2)="SV",Fields!Question_Code.Value,nothing)

Survey independent =IIF(Left(Fields!Question_Code.Value, 2)="SI",Fields!Question_Code.Value,nothing)

and so on...

But i keep getting an error :

A Value expression used for the report parameter ��QuestionCode�� refers to a field. Fields cannot be used in report parameter expressions.

[rsFieldInReportParameterExpression] A Value expression used for the report parameter ��QuestionCode�� refers to a field. Fields cannot be used in report parameter expressions.

[rsFieldInReportParameterExpression] A Value expression used for the report parameter ��QuestionCode�� refers to a field.

what am i doing wrong?

|||

I believe that if you are populating values for a parameter, you can't use the same dataset used in the report. I vaguely remember running into the same problem when I fist began using parameters. We use separate datasets for the parameters in our reports.

|||

Create a second dataset with the following query:

Select Distinct Left(Question_Code, 2)

FROM dbo.Qry_Questions

Group by Question_Code

Order by Question_Code

Change your parameter to query and point it at this new dataset. Then in your main dataset query add the following to your where statement:

Where Question_Code IN(@.question_code_parm)

|||Thanks that worked beautifully!! And i was able to hard code and rename the Question codes that were group for report parameters.

Grouping parameter value

I'm working on a stored procedure that works fine. I just want to make it possible for the user to be able to have a drop down list in reporting services to display the "question codes" grouped by whatever the first two digits are. for example.

VT01

VT02

VT03

VN01

VN02

VN03

ST01

ST02

ST03

instead of listing everything, i want the viewers to see this

VT

VN

ST

or an alias for each of these like this:

Vet Tasks

Vet National

Survey Tasks

Survey National

any ideas, here's my current code, which is pullin up anything with the added substring part

Code Snippet

ALTER PROCEDURE [dbo].[Testing_Questions]

(@.Region_Key int=null,@.QuestionCode char(5))

AS

BEGIN

SELECT dbo.Qry_Questions.Territory,

dbo.Qry_Questions.SalesResponsible,

dbo.Qry_Questions.Customer,

dbo.Qry_Questions.Date,

dbo.Qry_Questions.StoreName,

dbo.Qry_Questions.PostCode,

dbo.Qry_Questions.Address2,

dbo.Qry_Questions.[Question Code],

dbo.Qry_Questions.Question,

dbo.Qry_Questions.[Response Type],

dbo.Qry_Questions.response,

dbo.Qry_Questions.sales_person_code,

dbo.Qry_Sales_Group.Region_Key,

dbo.Qry_Sales_Group.Region

FROM dbo.Qry_Questions

INNER JOIN dbo.Qry_Sales_Group

ON dbo.Qry_Questions.sales_person_code COLLATE SQL_Latin1_General_CP1_CI_AS = dbo.Qry_Sales_Group.SalesPerson_Purchaser_Code

WHERE REGION_KEY=@.Region_Key

AND SUBSTRING(dbo.Qry_Questions.[Question Code],0,3)=@.QuestionCode

END

SET NOCOUNT OFF

You might try using the follwing as the grouping expression:

Code Snippet

=Left(Fields!<your_field>.Value, 2)

From there you could either set up a CASE statement or code for your aliases.

Hope this helps!

Scott

|||

I have the report working, i just want to be able to group the choices into 6 different choices. I know there is a way to do this in the report parameters properties box. I created my own non queried values that look like this:

Label Value

Survey national =IIF(Left(Fields!Question_Code.Value, 2)="SN",Fields!Question_Code.Value,nothing)

Survey vet =IIF(Left(Fields!Question_Code.Value, 2)="SV",Fields!Question_Code.Value,nothing)

Survey independent =IIF(Left(Fields!Question_Code.Value, 2)="SI",Fields!Question_Code.Value,nothing)

and so on...

But i keep getting an error :

A Value expression used for the report parameter ��QuestionCode�� refers to a field. Fields cannot be used in report parameter expressions.

[rsFieldInReportParameterExpression] A Value expression used for the report parameter ��QuestionCode�� refers to a field. Fields cannot be used in report parameter expressions.

[rsFieldInReportParameterExpression] A Value expression used for the report parameter ��QuestionCode�� refers to a field.

what am i doing wrong?

|||

I believe that if you are populating values for a parameter, you can't use the same dataset used in the report. I vaguely remember running into the same problem when I fist began using parameters. We use separate datasets for the parameters in our reports.

|||

Create a second dataset with the following query:

Select Distinct Left(Question_Code, 2)

FROM dbo.Qry_Questions

Group by Question_Code

Order by Question_Code

Change your parameter to query and point it at this new dataset. Then in your main dataset query add the following to your where statement:

Where Question_Code IN(@.question_code_parm)

|||Thanks that worked beautifully!! And i was able to hard code and rename the Question codes that were group for report parameters.

Grouping order conditionally?!

Hi,
I have a matrix with some groups and data.
I am passing a parameter called "theSort" to the report which is either "T"
or "C"
Two groups are TITLE and COUNTRY
If "T" is passed I would like the matrix to put TITLE first (in the first
column in matrix) and then COUNTRY after it. If "C" is passed then vice versa.
Is this possible' It didn't seem to work when I tried the following:
In the matrix's group tab, I put expressions for each group like so...
For Title group i put:
=IIF(Parameters!theSort Is "T",Fields!Title.Value,Fields!Country.Value)
For Country group i did:
=IIF(Parameters!theSort Is "T",Fields!Country.Value,Fields!Title.Value)
Didnt work.
Any help appreciated.
regards
KSTry =IIF(Parameters!theSort.Value ="T",Fields!Title.Value,Fields!Country.Value)
Fang Wang (MSFT)
Microsoft SQL Server Reporting Services
This posting is provided "AS IS" with no warranties, and confers no rights.
"saleek" <saleek@.discussions.microsoft.com> wrote in message
news:7787C07F-EF50-4E21-83C8-EA2E37DF3531@.microsoft.com...
> Hi,
> I have a matrix with some groups and data.
> I am passing a parameter called "theSort" to the report which is either
"T"
> or "C"
> Two groups are TITLE and COUNTRY
> If "T" is passed I would like the matrix to put TITLE first (in the first
> column in matrix) and then COUNTRY after it. If "C" is passed then vice
versa.
> Is this possible' It didn't seem to work when I tried the following:
> In the matrix's group tab, I put expressions for each group like so...
>
> For Title group i put:
> =IIF(Parameters!theSort Is "T",Fields!Title.Value,Fields!Country.Value)
> For Country group i did:
> =IIF(Parameters!theSort Is "T",Fields!Country.Value,Fields!Title.Value)
> Didnt work.
> Any help appreciated.
> regards
> KS

Grouping on Multi-Value parameter

I have a report that groups on a field, AccountNumber (which is a parameter)
I changed this param to a Multi-Value field, but now, whenever the report
runs, it blows up saying it's an invalid datatype for the grouping. I have
the rest figured out (how to parse the comma separated list) but I'm stumped
on this. Any ideas?
I know that when you change a parameter to multi-select, the value is
represented differently even if it's just one field that's being selected -
well, at least I think I know b/c my logic stopped working. I changed the
stored proc to parse the comma-separated values and all was well. So it's
working fine on every report that doesn't involve grouping. But on this one,
it blows up.
Thanks,
BillU¿ytkownik "W.G. Ryan [eMVP]" <WGRyaneMVP@.discussions.microsoft.com> napisa³
w wiadomo¶ci news:0DDCF3A4-61D8-4519-ADCC-F22C0B883898@.microsoft.com...
>I have a report that groups on a field, AccountNumber (which is a
>parameter)
> I changed this param to a Multi-Value field, but now, whenever the report
> runs, it blows up saying it's an invalid datatype for the grouping. I have
> the rest figured out (how to parse the comma separated list) but I'm
> stumped
> on this. Any ideas?
If your report dataset is based on SQL 2000/2005 you can prepare SQL
statement like this
SELECT * FROM table WHERE id in (@.MultiValueParam)
Regards
Adam|||"Adam Kobylinski" wrote:
> U¿ytkownik "W.G. Ryan [eMVP]" <WGRyaneMVP@.discussions.microsoft.com> napisa³
> w wiadomo¶ci news:0DDCF3A4-61D8-4519-ADCC-F22C0B883898@.microsoft.com...
> >I have a report that groups on a field, AccountNumber (which is a
> >parameter)
> > I changed this param to a Multi-Value field, but now, whenever the report
> > runs, it blows up saying it's an invalid datatype for the grouping. I have
> > the rest figured out (how to parse the comma separated list) but I'm
> > stumped
> > on this. Any ideas?
> If your report dataset is based on SQL 2000/2005 you can prepare SQL
> statement like this
> SELECT * FROM table WHERE id in (@.MultiValueParam)
> Regards
> Adam
>
Thanks Adam. Actually, I got the IN part to work. I couldn't get it to
work using the exact syntax you used, I had to parse the values out but I got
that to work.
The problem though is that the report creaters grouped on a Parameter as
opposed to a field in the dataset. However, when it was changed to a
multi-valued parameter, the grouping blew up.
I got around it by changing it so that it grouped on a report field instead
of the parameter. Any ideas though on how to get it to group on the
parameter if it's multi-valued?

Friday, March 23, 2012

Grouping and Filters

Hi everyone

I am using SSRS2005 with an SSAS cube building in BI

I need to create a custom grouping. Here's what i mean:

I give my period parameter some default Values. Like :
Period = 200501,200502,200601,200602
Now when building the report, I filter 2 Tables on the 2 years respectively.
Grouped by Period

So one table list all the Measures for 2005 and the other for 2006.
Now I want to use a Chart to Display the two totals. I can only get the Chart to
display the by monthley periods. IE:

30 o
|--|-||
20 o o
|--|-||
10 o
|--|-||
200501 200502 200601 200602 (instead of 2005 and 2006 as I need)

I need to create a grouping by which i can tell the chart what data to use.
I can't group by period.year because the Period field is an Integer

Any help is greatly appreciated
If I am unclear about anything please point it out to me

Thanks in advance
Gerhard Davids

Ok

So I sorted this out and it seems I was being really retarded.

I used the following statments in the grouping of the Chart.

Series group : =iif(Left(CStr(Fields!Period.Value),4) = "2004", 2004, iif(Left(CStr(Fields!Period.Value),4) = "2005",2005,iif(Left(CStr(Fields!Period.Value),4) = "2006",2006,Nothing)))

Category group : =iif(Right(Cstr(Fields!Period.Value),2) = "01" ,01,iif(Right(Cstr(Fields!Period.Value),2) = "02",02,iif(Right(Cstr(Fields!Period.Value),2) = "03",03,iif(Right(Cstr(Fields!Period.Value),2) = "04",04,iif(Right(Cstr(Fields!Period.Value),2) = "05",05,iif(Right(Cstr(Fields!Period.Value),2) = "06",06,iif(Right(Cstr(Fields!Period.Value),2) = "07",07,iif(Right(Cstr(Fields!Period.Value),2) = "08",08,iif(Right(Cstr(Fields!Period.Value),2) = "09",09,iif(Right(Cstr(Fields!Period.Value),2) = "10",10,iif(Right(Cstr(Fields!Period.Value),2) = "11",11,iif(Right(Cstr(Fields!Period.Value),2) = "12",12,iif(Right(Cstr(Fields!Period.Value),2) = "13",13,Nothing)))))))))))))

This allowed it to group the periods together but seperate for each year
and in the series explanation it gave me the total for
each year respectiveley.

In the data section I then simply sumed my measure

G

Monday, March 12, 2012

Group Case Sensitive

It appears that table grouping is case sensitive (for example, Re-Roof versus Re-roof appears to be causing a group break). I can't find a parameter to change this behaviour in Reporting Services.
Can anyone verify that it is in fact case sensitive? How to change?

I am running SQL Server 2000 and the database that I am querying is not case sensitive.

In report designer, edit the dataset properties, go to the "Data Options" tab and for the Case Sensitivity property select "False" instead of "Auto".

-- Robert

|||Made the suggested change and it didn't affect the report grouping.
After a little experiment, I can say the group break is definitely case sensitive.|||

Note: you can also just change the grouping expression to make it case-insensitive by applying the LCase() function which converts the string to lower case:

=LCase(Fields!Group.Value)

-- Robert

|||Just now saw the LCase response and tested it on the problem report. It did solve the problem!|||

Just a clarification on what I have found in this case.

Since DataRegion/DataSet/Grouing can be used for scoping puproses I thought it would be good to broaden this case sensitivity to include all of these.

What I found was the following on how RS compares names (short form 'I' for Case Insensitive and 'S' for Case Sensitive):

a) Grouping - S ("a" is different then "A")

b) DataSet - I

c) DataRegion - I

d) Grouping to DataSet - S (Grouping "A" can exist even if DataSet "a" exists)

e) Grouping to DataRegion - I

f) DataSet to DataRegion - I

I am perplexed as to why situations a) and especially d) exist. But it appears to be the way things work.

DK

|||Dataset fields are also S. It's probably because the report definition is compiled to a .NET assembly but I am all for (I).|||

Teo is regarding case-sensitiveness. The main reason is how the ReportObjectModel works and that making scope names case-insensitive would have a negative overall performance impact.

-- Robert

Group Case Sensitive

It appears that table grouping is case sensitive (for example, Re-Roof versus Re-roof appears to be causing a group break). I can't find a parameter to change this behaviour in Reporting Services.
Can anyone verify that it is in fact case sensitive? How to change?

I am running SQL Server 2000 and the database that I am querying is not case sensitive.

In report designer, edit the dataset properties, go to the "Data Options" tab and for the Case Sensitivity property select "False" instead of "Auto".

-- Robert

|||Made the suggested change and it didn't affect the report grouping.
After a little experiment, I can say the group break is definitely case sensitive.|||

Note: you can also just change the grouping expression to make it case-insensitive by applying the LCase() function which converts the string to lower case:

=LCase(Fields!Group.Value)

-- Robert

|||Just now saw the LCase response and tested it on the problem report. It did solve the problem!|||

Just a clarification on what I have found in this case.

Since DataRegion/DataSet/Grouing can be used for scoping puproses I thought it would be good to broaden this case sensitivity to include all of these.

What I found was the following on how RS compares names (short form 'I' for Case Insensitive and 'S' for Case Sensitive):

a) Grouping - S ("a" is different then "A")

b) DataSet - I

c) DataRegion - I

d) Grouping to DataSet - S (Grouping "A" can exist even if DataSet "a" exists)

e) Grouping to DataRegion - I

f) DataSet to DataRegion - I

I am perplexed as to why situations a) and especially d) exist. But it appears to be the way things work.

DK

|||Dataset fields are also S. It's probably because the report definition is compiled to a .NET assembly but I am all for (I).|||

Teo is regarding case-sensitiveness. The main reason is how the ReportObjectModel works and that making scope names case-insensitive would have a negative overall performance impact.

-- Robert

Group Case Sensitive

It appears that table grouping is case sensitive (for example, Re-Roof versus Re-roof appears to be causing a group break). I can't find a parameter to change this behaviour in Reporting Services.
Can anyone verify that it is in fact case sensitive? How to change?

I am running SQL Server 2000 and the database that I am querying is not case sensitive.

In report designer, edit the dataset properties, go to the "Data Options" tab and for the Case Sensitivity property select "False" instead of "Auto".

-- Robert

|||Made the suggested change and it didn't affect the report grouping.
After a little experiment, I can say the group break is definitely case sensitive.
|||

Note: you can also just change the grouping expression to make it case-insensitive by applying the LCase() function which converts the string to lower case:

=LCase(Fields!Group.Value)

-- Robert

|||Just now saw the LCase response and tested it on the problem report. It did solve the problem!|||

Just a clarification on what I have found in this case.

Since DataRegion/DataSet/Grouing can be used for scoping puproses I thought it would be good to broaden this case sensitivity to include all of these.

What I found was the following on how RS compares names (short form 'I' for Case Insensitive and 'S' for Case Sensitive):

a) Grouping - S ("a" is different then "A")

b) DataSet - I

c) DataRegion - I

d) Grouping to DataSet - S (Grouping "A" can exist even if DataSet "a" exists)

e) Grouping to DataRegion - I

f) DataSet to DataRegion - I

I am perplexed as to why situations a) and especially d) exist. But it appears to be the way things work.

DK

|||Dataset fields are also S. It's probably because the report definition is compiled to a .NET assembly but I am all for (I).|||

Teo is regarding case-sensitiveness. The main reason is how the ReportObjectModel works and that making scope names case-insensitive would have a negative overall performance impact.

-- Robert

Group by Top # entered in as Parameter

Background: I have a report that groups by Item number and gives adds
up total amount for that item number. What I want to do is have the
user enter in a numeric value as a parameter such as 10, 15, 20, etc
that will then only display the TOP 10, 15, 20, etc (what they entered
in the parameter) total amounts on the report. Can anyone help me out,
Im sure this can be done but it gets tricky with the parameters thrown
in the mix. Any suggestions is much appreciated. Thanks!hi brent
you can do this w/o issue by using a stored procedure as the source dataset
(and having your 'TOP' value included as one of the parameters).
next, you are going to need to supply a dataset for the dropdown:
select '10' as topval
union
select '20' as topval
union
select '3....
if you plan on 'rolling your own' ASP.NET interface, you can preload the
values for the dropdown in HTML.
Rob
"Brent" wrote:
> Background: I have a report that groups by Item number and gives adds
> up total amount for that item number. What I want to do is have the
> user enter in a numeric value as a parameter such as 10, 15, 20, etc
> that will then only display the TOP 10, 15, 20, etc (what they entered
> in the parameter) total amounts on the report. Can anyone help me out,
> Im sure this can be done but it gets tricky with the parameters thrown
> in the mix. Any suggestions is much appreciated. Thanks!
>

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