Using Report Dataset in Custom Code

  • Hello,

    I'm searching for a solution to make this:

    Public Function dothis(datasetname as string) As Long

    ' now I wan't to access to the dataset with the name in "datasetname"

    ' how can I do that?

    ' I need this for a special/custom aggregation function, I can't use it in SQL because

    ' the dataset must be cachable ...

    End Function

    In a Textbox:

    =Code.dothis("dsProducts")

  • Custom aggregates can be done with CLR in SQL Server 2005 or later, but it's not usually necessary. What kind of custom aggregate are you looking to create? In many cases, the query sourcing your dataset can be modified to include additional columns, such that a combination of standard aggregates on those columns might be sufficient to achieve the desired result. Details of the query for your dataset as well as DDL for the underlying tables would be most useful.

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • Hi Steve,

    I must generate a median over the values in the a chart.

    I use a very simple function in custom code fΓΌr do this in a table:

    Like this:

    dim values As New System.Collections.ArrayList

    Function AddValue(newValue as decimal) As decimal

    values.Add(newValue)

    AddValue = newValue

    End Function

    Function GetMedian() as decimal

    Dim count As Integer = values.Count

    If (count > 0)

    values.Sort()

    GetMedian = values(count/2)

    End If

    End Function

    It works very fine in a table, but not in a chart.

  • So where are the chart values coming from? Couldn't they be derived from a dataset that has the values directly in it? I see no reason why that couldn't have the median value generated in the T-SQL - just not as your typical aggregate might be generated.

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • The Chart Values comes from a big SQL because the Filter comes from Parameters an must be filtert in the report controls to use schnapshots and other features from Report Manager.

    So I can't get the Median with TSQL, I don't know the WHERE Condition in this moment.

    Greetings

    Frank

  • Umm... why are you using Reporting Services to do the filtering? Why not pass the parameters to a stored procedure instead? That way, you'll have a complete dataset at some point within the sp, and then can further process it to determine the median.

    I've never heard of the RS "snapshot" concept, so please elaborate... (I'll look it up in BOL in the meantime) and what other features of RS depend on RS having filtering? That seems counterintuitive to me...

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • this is very complicatet, there are SOX and other rules why I must store the "values" as is.

    If I use a SP or any other SQL feature, the dataset includes only the filtered values, not all at this time.

  • Now that I know what a report snapshot is, there's no way to produce it without preconfigured parameters or at least default values for those parameters, and no way to change the parameters once the user is viewing that snapshot. Here's the relevant paragraph from Books Online:

    Not all reports can be configured to run as a snapshot. You cannot create a snapshot for a report that prompts users for credentials or uses Windows integrated security to get data for the report. If you want to run a parameterized report as a snapshot, you must specify a default parameter to use when creating the snapshot. In contrast with reports that run on demand, it is not possible to specify a different parameter value for a report snapshot once the report is open. Choosing a different parameter value would result in a new report processing request, which is not allowed.

    Thus I don't see the problem with calculating the median ahead of time. I know that SOX is Sarbanes-Oxley, and that has it's own set of headaches, but that has more to do with the confidentiality of certain information rather than the method of generating a numeric value, does it not?

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • Sorry, but I think I can't do this. Here is a sample:

    1 A

    2 A

    3 A

    4 B

    5 B

    6 B

    7 C

    8 C

    9 C

    The Median of all is: 5. If you filter the second column to c it will be 8. So I don't see any chance to do this in a tsql or any other place on the server side.

    Any Idea to do this with tsql ?

    Thanx

    Frank

  • From what you've previously posted, you indicated you were going to need to use the snapshot feature. As that will require any filtering already be done, what's the difficulty?

    Even from the example, it would be easy enough to create a table variable to hold the median value for each possible value of the field to be filtered, using a group by methodology. Said table variable could then be the right side of a left outer join, and thus the median value for all as well as the median value for each value of the filter field could be available to all rows in the dataset.

    If that's what will work for you, I'll have to work on some pseudo-code tomorrow, as it's too late for today.

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • Here's some code that you could adapt to your circumstances, although without more details, I can't determine the performance in your situation.

    DECLARE @data TABLE(

    RN int,

    ALLRN int,

    DATAVALUE int,

    DATAGROUP char(1),

    MINROW int,

    MAXROW int,

    HALFDIFFLOW int,

    HALFDIFFHIGH int,

    GROUPMEDIAN decimal(10,4),

    MINROWALL int,

    MAXROWALL int,

    HDIFFLOW int,

    HDIFFHIGH int,

    OVERALLMEDIAN decimal(12,4)

    )

    INSERT INTO @data (DATAVALUE, DATAGROUP)

    SELECT 1, 'A' UNION ALL

    SELECT 2, 'A' UNION ALL

    SELECT 3, 'A' UNION ALL

    SELECT 4, 'B' UNION ALL

    SELECT 5, 'B' UNION ALL

    SELECT 6, 'B' UNION ALL

    SELECT 7, 'C' UNION ALL

    SELECT 8, 'C' UNION ALL

    SELECT 9, 'C' UNION ALL

    SELECT 10, 'D' UNION ALL

    SELECT 11, 'D' UNION ALL

    SELECT 12, 'D' UNION ALL

    SELECT 13, 'D' UNION ALL

    SELECT 14, 'E'

    ;WITH GROUP_MEDIAN_RAW AS (

    SELECT ROW_NUMBER() OVER(PARTITION BY DATAGROUP ORDER BY DATAVALUE) AS RN,

    ROW_NUMBER() OVER(ORDER BY DATAGROUP, DATAVALUE) AS ALLRN,

    DATAVALUE, DATAGROUP

    FROM @data

    )

    UPDATE D

    SET RN = G.RN, ALLRN = G.ALLRN

    FROM @data AS D INNER JOIN GROUP_MEDIAN_RAW AS G

    ON D.DATAGROUP = G.DATAGROUP AND

    D.DATAVALUE = G.DATAVALUE

    ;WITH GROUP_MEDIAN_SELECTORS AS (

    SELECT DATAGROUP, MIN(RN) AS MINROW, MAX(RN) AS MAXROW, CAST(MAX(RN) - MIN(RN) AS decimal(10,4))/2 AS HALFDIFF

    FROM @data AS D

    GROUP BY DATAGROUP

    )

    UPDATE D

    SET MINROW = G.MINROW,

    MAXROW = G.MAXROW,

    HALFDIFFLOW = CAST(G.HALFDIFF AS int),

    HALFDIFFHIGH = CAST(G.HALFDIFF + 0.5 AS int)

    FROM @data AS D INNER JOIN GROUP_MEDIAN_SELECTORS AS G

    ON D.DATAGROUP = G.DATAGROUP

    UPDATE D

    SET GROUPMEDIAN = (

    SELECT AVG(CAST(DATAVALUE AS decimal(10,4)))

    FROM @data AS D2

    WHERE D2.DATAGROUP = D.DATAGROUP AND

    D2.RN IN (D.MINROW + D.HALFDIFFLOW, D.MINROW + D.HALFDIFFHIGH)

    )

    FROM @data AS D

    DECLARE @MINA AS int, @MAXA AS int

    SELECT @MINA = MIN(ALLRN)

    FROM @data

    SELECT @MAXA = MAX(ALLRN)

    FROM @data

    ;WITH OVERALL_MEDIAN_SELECTORS AS (

    SELECT DATAGROUP, DATAVALUE, @MINA AS MINROW, @MAXA AS MAXROW,

    CAST(@MAXA - @MINA AS decimal(12,4))/2 AS HDIFF

    FROM @data

    )

    UPDATE D

    SET MINROWALL = G.MINROW,

    MAXROWALL = G.MAXROW,

    HDIFFLOW = CAST(G.HDIFF AS int),

    HDIFFHIGH = CAST(G.HDIFF + 0.5 AS int)

    FROM @data AS D INNER JOIN OVERALL_MEDIAN_SELECTORS AS G

    ON D.DATAGROUP = G.DATAGROUP AND

    D.DATAVALUE = G.DATAVALUE

    UPDATE D

    SET OVERALLMEDIAN = (

    SELECT AVG(CAST(DATAVALUE AS decimal(12,4)))

    FROM @data AS D2

    WHERE D2.ALLRN IN (D.MINROWALL + D.HDIFFLOW, D.MINROWALL + D.HDIFFHIGH)

    )

    FROM @data AS D

    SELECT *

    FROM @data

    This code has been tested on the sample data included, which expands somewhat on your sample data to ensure other data scenarios can be accommodated accurately. The median is computed for each group as well as overall, and included in every output record as appropriate. You'll have to adapt this to what you're doing as well as test for performance.

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • I need to do the same and struggeling to find a way to get access to the DataSources collection

    something like LocalReport.DataSources["myDataSource"].Value.

    any idea? Thanks in advance.

  • bendaia,

    You have to first tie a control on your report to a specific dataset, as otherwise, only aggregate functions for a given dataset are available in Reporting Services. Individual textboxes and similar controls cannot be tied to a dataset, and are thus limited. Table and matrix controls tie to a specific dataset, and then you access the Fields in that dataset as something like the following:

    =Left(Fields!FirstName.Value,1)

    Does that help?

    Steve

    (aka smunson)

    :):):)

    Steve (aka sgmunson) πŸ™‚ πŸ™‚ πŸ™‚
    Rent Servers for Income (picks and shovels strategy)

  • Has any one tried calculating median in SSRS 2005 where group by is used? The requirement is to calculate median for individual groups in a dataset?

    - Regards

    Dinesh

  • Has any one tried calculating median in SSRS 2005 where group by is used? The requirement is to calculate median for individual groups in a dataset?

    Here's a method using T-SQL:

    -- setup

    IF OBJECT_ID('tempdb..#test_table','U') IS NOT NULL

    DROP TABLE #test_table;

    --

    CREATE TABLE #test_table(

    [colA] [tinyint] NULL,

    [colB] [char](1) NULL

    ) ON [PRIMARY];

    -- test data

    INSERT INTO #test_table(colA,colB)

    SELECT 1,'A' UNION ALL

    SELECT 2,'A' UNION ALL

    SELECT 3,'A' UNION ALL

    SELECT 4,'B' UNION ALL

    SELECT 5,'B' UNION ALL

    SELECT 6,'B' UNION ALL

    SELECT 7,'C' UNION ALL

    SELECT 8,'C' UNION ALL

    SELECT 9,'C' UNION ALL

    SELECT 10,'C'

    -- return median values (grouped by colB)

    SELECT X.colB, AVG(1.0*X.colA) AS median

    --INTO #temp2

    FROM

    ( SELECT colB, colA, ROW_NUMBER() OVER(PARTITION BY colB ORDER BY colA) AS rowno

    FROM #test_table

    ) X

    INNER JOIN

    ( SELECT colB, 1+count(*) AS N

    FROM #test_table

    GROUP BY colB

    ) Y

    ON X.colB = Y.colB AND X.rowNo BETWEEN N/2 AND N/2+N%2

    GROUP BY X.colB

    Note that the number of rows where colB = 'C' is even so there is no true 'median', hence the average value is returned

Viewing 15 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic. Login to reply