Showing posts with label guys. Show all posts
Showing posts with label guys. Show all posts

Friday, March 30, 2012

Grouping question

Hi guys,

on my report i have 3 separate matrices with monthly sales results, each gives a different view on the same data. This all works nicely, but the customer wants these matrices grouped by product (the product is a parameter of the report, they can choose several or all products to report on).

Exactly what would be the best way to achieve this grouping? It seems i can't house them within a table, and i can't put them in another matrix without running into scope errors.

Thanks!!!

sluggy

Sounds like those three matrics are using the same dataset. In that case, you should be able to remove the dataset set on these matrices respectively. Add a list that includes the three matrices, set the dataset on the list, and add a group on the list by the product.|||

Thanks Fang,

that did the trick nicely.

One further (possibly stupid) question: how could i then have a set of matrices at the end with the totals (ie the aggregations across all products)? Should i just have a copy of the original matrices and make them invisible if there was only one product selected? Or is there a more proper or cooler way to do it?

Many thanks,

sluggy

|||

There are multiple ways to do this:

1. Add a copy of the original matrices outside of the list.

2. Use a matrix instead of list to host the three matrices, add a matrix row group by product, and enable subtotal on the row group. This way you will automatically get the matrics across all products in the subtotal row.

|||

Excellent, thanks!!

sluggy

Monday, March 26, 2012

Grouping data by x-axis labels

Hey guys,

I have thousands of records in the data source(i.e. Cube), which includes datetime information. I want to aggregate and present the data on a bar chart on monthly basis. That means the interval between the dates should be one month. Assume that the dates value will be labeled on the x-axis of the bar chart.

I tried to find out the solution for many days. I will really appreciate if anybody give me some idea.

Sincerely,

Amde

Try creating a category group with two expressions, using the following grouping expressions.

=Fields!DateField.Value.Year
=Fields!DateField.Value.Month

For the label you could use something like, =Fields!DateField.Value.ToShortDateString()

You could also use two category groups, if you wanted an inner set of labels for the month and another outer set for the year.|||

Hi,

Thank youy for your feedback, however that doesn't solve my problem: here is the thing;

I created a bar chart report. The x-axis value of this chart is a timestamp(datetime) field of a dimension. Thousands of records are inserted in to this field everyday, as a result, I will have the timestamp information every second or minute. So here is the thing, If for instance, I want to present last 5 months data in the bar chart(x-axis), the chart can not accomodate all the data and it doesn't look good to present a data which occured every minute or hours. So I want to present the data on monthly basis based on the StartDate and EndDate parameters value provided by the user.

Assume the user wants to preview 5 months record from 2006-03-04 to 2006-07-04, the data should be aggregated and presented on monthly basis as shown below, instead of directly displaying all the data as they appear in the dataset.


2006-03-04 2006-04-04 2006-05-04 2006-06-04 2006-07-04

Please let me know if you need more clarification.

Sincerely,

Amde

|||Adding the category fields with the groupings mentioned above should produce the grouping structure you are looking for. When you tried it what happened that was incorrect?

The bounds provided by the StartDate and EndDate parameters can either be used in the the sql query. Or, if it can't be done there, then you can set a filter for the category group. Also, the reason there is a group expression for Year is that the data may span multiple years and I'm assuming that you don't want the data for the same month in multiple years to be aggregated together.

Here is a sample report that uses the northwind database to show the number of orders placed for each month. It contains a bar chart and two parameters, which are used in the sql query.

<?xml version="1.0" encoding="utf-8"?>
<Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
<DataSources>
<DataSource Name="Northwind">
<ConnectionProperties>
<IntegratedSecurity>true</IntegratedSecurity>
<ConnectString>Data Source=localhost; Initial Catalog=Northwind</ConnectString>
<DataProvider>SQL</DataProvider>
</ConnectionProperties>
<rd:DataSourceID>40232364-d6a5-4917-bcad-13308e3a8f62</rd:DataSourceID>
</DataSource>
</DataSources>
<BottomMargin>1in</BottomMargin>
<RightMargin>1in</RightMargin>
<ReportParameters>
<ReportParameter Name="StartDate">
<DataType>DateTime</DataType>
<DefaultValue>
<Values>
<Value>7/1/1996</Value>
</Values>
</DefaultValue>
<AllowBlank>true</AllowBlank>
<Prompt>Start Date</Prompt>
</ReportParameter>
<ReportParameter Name="EndDate">
<DataType>DateTime</DataType>
<DefaultValue>
<Values>
<Value>11/30/1996</Value>
</Values>
</DefaultValue>
<AllowBlank>true</AllowBlank>
<Prompt>End Date</Prompt>
</ReportParameter>
</ReportParameters>
<rd:DrawGrid>true</rd:DrawGrid>
<InteractiveWidth>8.5in</InteractiveWidth>
<rd:SnapToGrid>true</rd:SnapToGrid>
<Body>
<ReportItems>
<Chart Name="chart1">
<Legend>
<Visible>true</Visible>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
</Style>
<Position>RightCenter</Position>
</Legend>
<Subtype>Plain</Subtype>
<Title />
<Height>5.125in</Height>
<CategoryAxis>
<Axis>
<Title />
<MajorGridLines>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
</Style>
</MajorGridLines>
<MinorGridLines>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
</Style>
</MinorGridLines>
<MajorTickMarks>Outside</MajorTickMarks>
<Min>0</Min>
<Margin>true</Margin>
<Visible>true</Visible>
</Axis>
</CategoryAxis>
<PointWidth>0</PointWidth>
<Left>0.375in</Left>
<ThreeDProperties>
<Rotation>30</Rotation>
<Inclination>30</Inclination>
<Shading>Simple</Shading>
<WallThickness>50</WallThickness>
</ThreeDProperties>
<DataSetName>Northwind</DataSetName>
<Top>0.125in</Top>
<PlotArea>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
<BackgroundColor>LightGrey</BackgroundColor>
</Style>
</PlotArea>
<ValueAxis>
<Axis>
<Title />
<MajorGridLines>
<ShowGridLines>true</ShowGridLines>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
</Style>
</MajorGridLines>
<MinorGridLines>
<Style>
<BorderStyle>
<Default>Solid</Default>
</BorderStyle>
</Style>
</MinorGridLines>
<MajorTickMarks>Outside</MajorTickMarks>
<Min>0</Min>
<Margin>true</Margin>
<Visible>true</Visible>
<Scalar>true</Scalar>
</Axis>
</ValueAxis>
<Type>Bar</Type>
<Width>6.5in</Width>
<CategoryGroupings>
<CategoryGrouping>
<DynamicCategories>
<Grouping Name="chart1_CategoryGroup1">
<GroupExpressions>
<GroupExpression>=Fields!OrderDate.Value.Year</GroupExpression>
<GroupExpression>=Fields!OrderDate.Value.Month</GroupExpression>
</GroupExpressions>
</Grouping>
<Label>=MonthName(Fields!OrderDate.Value.Month)</Label>
</DynamicCategories>
</CategoryGrouping>
</CategoryGroupings>
<Palette>Default</Palette>
<ChartData>
<ChartSeries>
<DataPoints>
<DataPoint>
<DataValues>
<DataValue>
<Value>=Count(Fields!OrderID.Value)</Value>
</DataValue>
</DataValues>
<DataLabel />
<Marker>
<Size>6pt</Size>
</Marker>
</DataPoint>
</DataPoints>
</ChartSeries>
</ChartData>
<Style>
<BackgroundColor>White</BackgroundColor>
</Style>
</Chart>
</ReportItems>
<Height>5.75in</Height>
</Body>
<rd:ReportID>6323408e-15e1-4a7f-8151-ac96e7ebf862</rd:ReportID>
<LeftMargin>1in</LeftMargin>
<DataSets>
<DataSet Name="Northwind">
<Query>
<rd:UseGenericDesigner>true</rd:UseGenericDesigner>
<CommandText>="SELECT OrderDate, OrderID FROM Orders WHERE Orders.OrderDate BETWEEN '" & Parameters!StartDate.Value & "' AND '" & Parameters!EndDate.Value & "'"</CommandText>
<DataSourceName>Northwind</DataSourceName>
</Query>
<Fields>
<Field Name="OrderDate">
<rd:TypeName>System.DateTime</rd:TypeName>
<DataField>OrderDate</DataField>
</Field>
<Field Name="OrderID">
<rd:TypeName>System.Int32</rd:TypeName>
<DataField>OrderID</DataField>
</Field>
</Fields>
</DataSet>
</DataSets>
<Width>9.375in</Width>
<InteractiveHeight>11in</InteractiveHeight>
<Language>en-US</Language>
<TopMargin>1in</TopMargin>
</Report>|||

Yes, that is correct. The assumption, group expression for year is also correct.

Thank you for your cooperation.

sql

Grouping container, is there any limitation?

hi guys,

I was wondering about a silly thing but, anyway, which is the maximum number of grouping for a container? I mean, when you group from, i.e, a sql task and then over that group do again another one and so on...

Thanks in advance for your time,

Don't quote me on this, but I'm assuming that a container just has a container for children effectively creating a linked list. So the limit should be memory or the level that .Net would allow say For loops to be nested.|||thanks a lot

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