Report Calculations: SSRS Source Query vs Expressions

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 won’t 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:
(cont’d)
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 isn’t a calculation that is likely to change, so
it’s 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
don’t 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
we’re 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 don’t 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 it’s 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 isn’t 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 don’t 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 there’s probably
some logic there – and it’s nice to centralize it
where it’s 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 isn’t finicky – it works like
the T-SQL case).
There’s 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 it’s 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 isn’t a calculation that is likely to change, so it’s
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 isn’t a calculation that is likely to change, so
it’s 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
(cont’d)
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
Don’t forget to download the cheat sheet!
Creative Commons License:
Attribution-NonCommercial-NoDerivative Works 3.0