You are on page 1of 78

Report Calculations:

SSRS Source Query


vs Expressions
SQL Saturday #70 Columbia, SC
3/19/2011
Melissa Coates

About Me
Melissa is a Business Intelligence

developer based in Charlotte, NC


Consultant with Mariner, specializing in
BI and Data Warehousing solutions
using the Microsoft platform
MCITP and MCTS in BI

Melissa Coates
Blog:
http://www.sqlchick.com
Twitter: @sqlchick

About Mariner
http://www.mariner-usa.com

Other Presentations Today


Who

Topic

Time

Bill Pearson

Design and Implement BI Like


Edison

9:45 am

Bill Pearson

Entity Strategies: Structuring


Your Consultancy

1:15 pm

Melissa Coates

Report Calculations: SSRS


Source Query vs. Expressions

1:15 pm

Wayne Snyder

Information: Are You Blinded by


the Light?

2:30 pm

Javier Guillen

DAX Formulas: Evaluation


Context

3:45 pm

Agenda
Overview: Terms & Types of Functions
Compare several functions between T-SQL and SSRS
Syntax
Report impact
Differences in functionality
Differences in results returned

Goal for Today


Identify common situations when performing calculations
within SSRS is preferred, versus when T-SQL is more
appropriate

Scope of Discussion
Source query: SQL Server relational data sources

SSRS functions: expressions within a text box


We wont be extending this discussion to custom code
Performance statistics shown are from my laptop

(Dell Latitude, 64-bit, Windows 7, 2.53GHz, 8GB RAM)

Examples
Most examples use AdventureWorksDW2008R2
A few use AdventureWorks2008R2

Concerns of a
Report Developer

Concerns of a Report Developer


Accuracy

Performance
Maintenance
Reusability
Standardization
Security
Testing
Deployment

Documentation

....etc

Managing Hefty Calculations


1st choice: Calculations are predefined in the source
data (ex: handled by ETL)
2nd choice: Calculations are centralized in a reusable
stored procedure or function within the database
3rd choice: Calculations are centralized in an SSRS
source query (R2 makes this easier with shared datasets)
4th choice: Calculations are embedded within
expressions inside an individual report

Overview:
Terms & Types of Functions

Function
A portion of code which performs a specific task
In other languages, called a procedure, method, or subroutine
Functions can be built-in, or user-defined
In T-SQL, functions are usually used to query the data, or perform operations on data

MSDN:

Function

SSMS
query:
SSMS
object
explorer:

(contd)

Expression
In T-SQL, expressions are:
A combination of symbols and
operators which are evaluated
to return a single data value.
**In T-SQL: the expression is
evaluated individually for each row in
the result set.**
An expression may or may not

contain a function.
Simple expressions can be a
single constant, variable,
column, or scalar function.
Operator symbols can be used
to join 2 or more simple
expressions into a complex
expression.

In SSRS, expressions are:


Written in VB.Net
Refers to constants, operators,
functions, fields, collections,
variables, and/or custom code

4 Types of T-SQL Functions


Type

Description

Examples

Rowset

Returns object that can be used like


table references in a SQL
statement.

OpenRowset, OpenQuery

Ranking

Returns a ranking value for each


row in a partition.

Rank, Ntile, Row_Number

Aggregate

Operates on a collection of values, Sum, Avg, Min, Max, Count


but returns a single summarizing
value.

Scalar

Operates on a single value, and


also returns a single value. Scalar
values are used wherever an
expression is valid. Includes:
Date and Time functions
Mathematical functions
String functions
.among many others

GetDate, DatePart, DateDiff,


Abs, Round, Case,
Cast, Convert, Lower, Upper,
Len, LTrim, RTrim

9 Types of SSRS Functions


Type

Description

Examples

Aggregate

Summarize values for a


set of non-null numeric
data

Avg, Count, First, Last, Sum

Text

Operates on a textual
(string) value

FormatNumber, Join, Replace,


StrComp, RTrim, UCase

Date & Time

Operates on date and


time values

DateAdd, DateDiff, FormatDateTime,


Now, Today

Program Flow Conditional logic

Choose, IIF, Switch

Misc

Miscellaneous

InScope, Level, Lookup, LookupSet,


MultiLookup, Previous, RowNumber

Financial

Calculates numeric values Pmt, Rate, FV, DDB

Math

Calculates numeric values Abs, Ceiling, Rnd

Inspection

Inspects the value &


returns info about it

IsNothing, IsDate, IsArray, IsNumeric

Conversion

Converts to another data


type

CInt, CDec, CChar

Cheat Sheet:
Comparisons Between T-SQL Functions
and SSRS Functions

Cheat Sheet
Available at:
http://www.sqlchick.com Presentations page

Part I:
Aggregate
Functions
Running Value
Average
Count

Calculating
Running Values

Running Value: Functions Available


A running aggregate of all non-null numeric values specified by the expression,
evaluated for the given scope.
T-SQL:

SSRS:

No built-in function.

Syntax:
=RunningValue(expression, function, scope)

Various options to handle


including:
CTE
Correlated subquery
Self join
Cross join
Temp table
etc

Example:
=RunningValue(Fields!SalesAmount.Value, Sum,
"ResellerSalesByYear")

Running Value: T-SQL


Dataset query:

Report body:

Report results:

Running Value: SSRS


Dataset query:

Report body:

Report results:

Running Value
T-SQL:
Execution Log:

SSRS:
Execution Log:

SSRS function: easier to implement.


SSRS function: more performant.
This isnt a calculation that is likely to change, so
its okay to embed in report.

SSRS

Average

Average: Functions Available


Average a numeric value, excluding nulls:
T-SQL:

SSRS:

SELECT AVG(Amount) or
SELECT AVG(ALL Amount)

=Avg(Fields!Amount.Value)

Average distinct, non-null, rows:


T-SQL:

SSRS:

SELECT AVG(DISTINCT Amount)

Not supported

Average: T-SQL
Dataset query:

Report body:

Report results:

ReorderPoint is an integer field. Even if we


format the report results as decimal(2), we
dont get decimals because T-SQL averaged
the integer.

Average: SSRS

Report body:

Dataset query:

Report results:

This query returns detail


rows which is okay if
were going to show the
detail on the report (i.e.,
drill-down +/- on the right).

Without
doing
anything
special, we
see the
decimals
when the
averaging
occurs in
SSRS.

Average: T-SQL Averaging an Integer


Dataset query:

This example is using an integer field.


If we cast to a decimal first, we can see
the decimals within the report results.
This is an extra step in T-SQL though.

Average: Aggregating an Aggregate


An average of an average is not usually the correct result.

Averaged in T-SQL
Averaged in
SSRS: results in
an average of
an average
which returns a
very different
result than if all
detail rows were
averaged.

Incorrect
(was calculated from average)

Correct
(was calculated from detail)

Average
Usually we want to average in the source query to
avoid bringing back extra data we dont need in the
report.

T-SQL

If the field being averaged is an integer, and you


want to see accurate decimal places, cast it first
before its averaged.
If you need a distinct Avg: this must be done in the
source query.

If you need the detail in the report anyway (ex: a


drill-down) then averaging in the report is okay &
might even save a cast operation.
When detail is present, SSRS is really good at
averaging per groups, and for the grand total.
Careful with performing an aggregate of an
aggregate (if underlying detail isnt in the report
query).

SSRS

Counts

Count: Functions Available


Count all rows, excluding nulls:
T-SQL:

SSRS:

SELECT COUNT(ALL Size)

=Count(Fields!Size.Value)

Count all rows, including nulls and duplicates:


T-SQL:

SSRS:

SELECT COUNT(*)

=CountRows()

Count distinct, non-null, rows:

The only Distinct function


available in SSRS

T-SQL:

SSRS:

SELECT COUNT(DISTINCT Size)

=CountDistinct(Fields!Size.Value)

Count: T-SQL
Dataset query:

Report body:

Report results:

Count: SSRS
Dataset query:

This query returns all


rows for no other
purpose than to
aggregate them
i.e., unnecessary
detail this is
typically not the most
optimal solution.

Report body:

Report results:

Count
T-SQL:
Profiler:
Execution Log:

SSRS:
Profiler:
Execution Log:

T-SQL

Usually we want to count in the source query to avoid


bringing back extra data we dont need in the report.

If you need the detail in the report anyway (ex: a drilldown) then counting in the report is okay to do.

SSRS

Part II:
Text & Formatting Functions
Return part of string
Trim trailing spaces
String comparisons
Formatting

Text (String) Functions Available


Return part of a string:
T-SQL:

SSRS:

SUBSTRING(SalesOrderNumber, 3,5)

=Mid(Fields!SalesOrderNumber.Value, 3,5)

LEFT(SalesOrderNumber, 2)

=Left(Fields!SalesOrderNumber.Value, 2)

RIGHT(SalesOrderNumber, 5)

=Right(Fields!SalesOrderNumber.Value, 5)

Trim trailing spaces:


T-SQL:

SSRS:

LTRIM(SalesOrderNumber)

=LTrim(Fields!SalesOrderNumber.Value)

RTRIM(SalesOrderNumber)

=RTrim(Fields!SalesOrderNumber.Value)

RTRIM(LTRIM(SalesOrderNumber))

=Trim(Fields!SalesOrderNumber.Value)

Text (String) Functions Available


String Comparisons:

1: textual comparison (case


insensitive)
0 or skipped: binary comparison

T-SQL:

SSRS:

SELECT SOUNDEX(
EnglishCountryRegionName)

=StrComp(
Fields!EnglishCountryRegionName.Value,
Fields!SpanishCountryRegionName.Value, 1)

SELECT DIFFERENCE(
EnglishCountryRegionName,
SpanishCountryRegionName)

Results: 0: same
1: string 1 > string 2
-1: string 1 < string 2

Formatting Functions Available


.NET codes are
supported

Two decimal places no commas:


T-SQL:

SSRS:

CAST(SalesAmount AS Dec(8,2))
CONVERT(DEC(8,2),SalesAmount)

=Format(Fields!SalesAmount.Value, "F2")
=Format(Fields!SalesAmount.Value, "##.##")

Two decimal places with commas:


T-SQL:

SSRS:

Not supported in T-SQL

=FormatNumber(Fields!SalesAmount.Value, 2)
=Format(Fields!SalesAmount.Value, "#,#.##")

Two decimal places with currency symbol:


T-SQL:

SSRS:

Not supported in T-SQL

=FormatCurrency(Fields!SalesAmount.Value, 2)
=Format(Fields!SalesAmount.Value, "C2")

Formatting Functions Available


Percentage:
T-SQL:

SSRS:

Not supported in T-SQL.

=FormatPercent(Fields!SalesPct.Value)

DateTime:
SSRS:

Text & Formatting Functions

This is what SSRS is meant for!

SSRS

Part III:
DateTime Functions
DATEPART
DATEADD
Current Date and Time

DateTime Functions Available


DATEPART and DATEADD:
T-SQL:

SSRS:

SELECT DATEPART(YY,ModifiedDate)

=DatePart(DateInterval.Year,
Fields!ModifiedDate.Value)

SELECT DATEADD(DAY,2,OrderDate)
=DateAdd(DateInterval.Day, 2,
Fields!ModifiedDate.Value)

Year
Quarter
Month
Week
Day
Hour

Minute
Second
Millisecond
Microsecond
Nanosecond

SSRS: precision
down to the second
T-SQL: more precise

DateTime Functions Available


Current Date and Time:

T-SQL Function

Returns

SELECT GETDATE()

2011-02-22 19:10:47.757

SELECT CURRENT_TIMESTAMP 2011-02-22 19:10:47.757


SELECT SYSDATETIME()

2011-02-22 19:10:47.7582404

SSRS Function

Returns

=Now()

2/22/2011 7:10:47 PM

=Globals!ExecutionTime

2/22/2011 7:10:47 PM

=Today()

2/22/2011 12:00:00AM

=DateString()

02-22-2011

=TimeString()

19:10:47

DateTime Functions
T-SQL

T-SQL is more precise.

SSRS is well formatted more closely


for presentation.

SSRS

Part IV:
Program Flow
Functions
CASE
IIF
Switch

Decoding Values

Decoding Values
Evaluates a list of conditions and returns one of multiple possible result expressions:
T-SQL:

SSRS:

Simple CASE (allows equality check only)


CASE ProductLine
WHEN 'R' THEN 'Road'
WHEN 'M' THEN 'Mountain'
WHEN 'T' THEN 'Touring'
WHEN 'S' THEN 'Other'
ELSE 'Not for sale'
END AS Category

=IIF(Fields!ProductLine.Value = "R","Road",
IIF(Fields!ProductLine.Value = "M","Mountain",
IIF(Fields!ProductLine.Value = "T","Touring",
IIF(Fields!ProductLine.Value = "S","Other",
Not For Sale"))))

SSRS:
Searched CASE:
CASE WHEN ProductLine = 'R' THEN 'Road'
WHEN ProductLine = 'M' THEN 'Mountain'
WHEN ProductLine = 'T' THEN 'Touring'
WHEN ProductLine = 'S' THEN 'Other'
ELSE 'Not for sale'
END AS Category

=Switch(
TRIM(Fields!ProductLine.Value) = "R","Road",
TRIM(Fields!ProductLine.Value) = "M","Mountain",
TRIM(Fields!ProductLine.Value) = "T","Touring",
TRIM(Fields!ProductLine.Value) = "S","Other",
IsNothing(Fields!ProductLine.Value),Not For Sale"
)

Decoding Values
T-SQL

The appeal of adding the Case statement to the


T-SQL source query is that theres probably
some logic there and its nice to centralize it
where its readily apparent.

Switch is equivalent to a Searched CASE


(i.e., can handle various operators). Usually
easier to read than a nested IIF.
Switch is finicky & needs a Trim, else it
may fail to find a match on a varchar field
(whereas the IIF isnt finicky it works like
the T-SQL case).
Theres not an ELSE in a Switch, so might
want to embed Switch within IIF.

SSRS

Part V:
Miscellaneous
Functions
Ranking
Row Number
Previous
Percent of Total

Scoping

Scoping in SSRS
Specifies what data to include in aggregate calculations.

Scope may be specified as any of these (using the Name property):


Dataset (i.e., the query - after filters are applied)
How would
Data Region (i.e., table, matrix, list, etc)
you
May the outer data region, or a nested data region
implement
this concept
Group
in T-SQL?
If a table: these are the Row and Column Groups
If a chart: these are the Series and Category Groups
May be groups for an outer data region, or a nested data region
Nothing
Uses the outermost Data Region scope available to the report item

Scoping in T-SQL
Specifies what field(s) to group by in aggregate calculations.

Scoping
T-SQL

Handled using the OVER() clause; result sets


are divided using PARTITION statements.

A little more straightforward to do within SSRS,


especially when source queries get more complex.
Scoping permitted for:
Dataset
Data Region
Group

SSRS

Ranking & Row Numbers

Ranking: Functions Available


Rank of each row within the partition:
T-SQL:

SSRS:

RANK() OVER (ORDER BY a.PostalCode)

Not supported

Rank of each row within the partition, without any gaps in numbering:
T-SQL:

SSRS:

DENSE_RANK() OVER (ORDER BY a.PostalCode)

Not supported

Distribute rows into a specified number of groups:


T-SQL:

SSRS:

NTILE(4) OVER (ORDER BY a.PostalCode)

Not supported

Sequential number of each row:


T-SQL:

SSRS:

ROW_NUMBER() OVER(ORDER BY SalesYTD DESC)


or
ROW_NUMBER() OVER(PARTITION BY PostalCode
ORDER BY SalesYTD DESC)

=RowNumber(Dset_YTDSales)
or
=RowNumber(Group_PostalCode)

Ranking and RowNumber: T-SQL

RowNumber: SSRS

Report body:

Dataset query:

Report results:

Ranking
T-SQL

If you need to do a Rank or an NTile, you must do it


within the source query.
Rank
Dense_Rank
NTile
Both scenarios can handle Row Numbers through
Scope or Partitions.

The RowNumber function in SSRS does very


nicely when its scoped, although the same thing
could be done in T-SQL with partitions.

SSRS

Percent of Total

Percent of Total: Functions Available


A running aggregate of all non-null numeric values specified by the expression,
evaluated for the given scope.
T-SQL:

SSRS:

No built-in function.

No built-in function. Handled gracefully, however,


using scoping in SSRS.

Various options to handle


including:
Common table expression
Correlated subquery
Self-join
Cross-join
etc

Example:
=FormatPercent(
Sum(Fields!SalesAmount.Value)
/
Sum(Fields!SalesAmount.Value,"Tablix1")
,1)
scope

Percent of Total: T-SQL


Dataset query:

Report body:

Report results:

Percent of Total: SSRS


Dataset query:

Report body:

Report results:

Percent of Total
T-SQL:
Execution Log:

SSRS:
Execution Log:

SSRS function: easier to implement.

This isnt a calculation that is likely to change, so its


okay to embed in report.

SSRS

Previous Row

Previous Row: Functions Available


Finding a value from the previous row:
T-SQL:

SSRS:

No built-in function.

=Previous(Fields!SalesAmount.Value)

Various options to handle


including:
Common table expression
Correlated subquery
Self join
Cross join
Temp table
etc

Previous Row: T-SQL


Dataset query:

Report body:

Report results:

Previous Row: SSRS


Dataset query:

Report body:

Report results:

Previous Row
T-SQL:
Execution Log:

SSRS:
Execution Log:

SSRS function: easier to implement.


SSRS function: more performant.
This isnt a calculation that is likely to change, so
its okay to embed in report.

SSRS

Conclusion

Recap
Aggregate Function

T-SQL

SSRS

Why?

Running Value

Built-in to SSRS

Average & Count

Depends on level of
detail

Text Function

T-SQL

SSRS

Why?

Return part of string

Same functionality

Trim trailing spaces

Trim both in 1 step

String comparisons

Quick & easy

Formatting

Far more functionality;


intended to be done in
report

Recap

(contd)

DateTime Function

T-SQL

SSRS

Why?

DatePart and DateAdd

More precision

Current Date

Same; formatted nicely

Program Flow
Function

T-SQL

SSRS

Decoding Values
(CASE vs IIF vs Switch)

Misc. Function

Why?
Centralize logic

T-SQL

SSRS

Why?

Ranking & Row Nbr

A lot more functionality

Percent of Total

Easy to do with scope

Previous Row

Built-in to SSRS

When Is SSRS Preferred?


If you need to Scope the calculation (a little more

straightforward than the Partitioning in T-SQL)


RunningValue (no built-in equivalent in T-SQL)
Previous (no built-in equivalent in T-SQL)
Percent of Total
Handling formatting
Trim (can do a Trim of left & right with one step)
String Comparisons (StrComp is very useful)
Lookups to another dataset
First and Last

When Is Source Query Preferred?


When you can centralize the logic (and SSRS would

duplicate or need to be done multiple times)


Aggregations, such as counting and averaging (can often
omit unneeded detail being sent to the report)
Ranking
Distinct (exception: CountDistinct)
User-Defined Functions

Questions &
Suggestions

References
Built-In Functions (Transact-SQL):
http://msdn.microsoft.com/en-us/library/ms174318.aspx

Expressions (Transaction-SQL):
http://msdn.microsoft.com/en-us/library/ms190286.aspx

Understanding Expression References (SSRS):


http://msdn.microsoft.com/en-us/library/cc281391(v=SQL.100).aspx

Using Built-In Report and Aggregate Functions in Expressions (SSRS):


http://msdn.microsoft.com/en-us/library/ms159673.aspx
http://technet.microsoft.com/en-us/library/ms159673(SQL.100).aspx

Understanding Expression Scope for Totals, Aggregates, and Built-In Collections (SSRS):
http://technet.microsoft.com/en-us/library/dd255256.aspx

Expression Examples (SSRS):


http://technet.microsoft.com/en-us/library/ms157328.aspx

Calculating Totals and Other Aggregates (SSRS):


http://technet.microsoft.com/en-us/library/bb630415.aspx

You might also like

To register:
https://www.clicktoattend.com/
invitation.aspx?code=154140
or
http://www.mariner-usa.com
Link to the Event will be at
bottom right of home page

Thanks for attending!


Melissa Coates
Blog:
http://www.sqlchick.com
Twitter: @sqlchick

Dont forget to download the cheat sheet!

Creative Commons License:


Attribution-NonCommercial-NoDerivative Works 3.0

You might also like