SQL Reporting "How to" - Conditional Color 1/4: The Basics. Report Expressions & Custom Code
This "How to" guide provides ideas & code samples on using color to improve your users understanding of the data in your reports. It includes using gradients of color in your tables & charts. It also covers using color to represent a second dimension &/or multiple levels of data in a hierarchy.
Applies to: SQL Server Reporting Services 2005 & SQL 2008 (I’ve not tested it on SQL 2000, nor the version to follow SQL2008, but I expect it will work ok, too.)
Part 1: Starts at the basics of Report Expressions & adding code to your reports.
Part 2: Shows the example code, to create ranges of color & shades within a color.
Part 3: Shows the example code, changing a single color from Bright to Light or Dark.
Part 4: Shows how to use them in charts & with multiple dimensions.
Contents - Part 1: Conditional Formatting: the Basics
1. Using a Report Expression.
Handy Report Expressions
Simple Conditional Coloring
2. Using a Custom Code
3. Using a other .NET Classes in your Custom Code
4. Using a Custom Assemblies
Appendix: Getting yourself started.
Overview
This 3 part blog is intended to show you how to create conditional formatting within your reports. Specifically changing the background colors of table cells to highlight ranges of values in cells. And to use Charts to display multiple dimensions ie: The length of the bar shows 1 measure (eg: Revenue) & the color a different measure (eg: Profitability).
Samples of what you can do formatting Fonts, Tables & Chart elements.
Conditional Formatting: the Basics.
SQL Reporting Services is incredibly flexible, there are many ways that it can be extended, enhanced &/or embedded. This post will limit itself to techniques commonly used by the average Report Author.
To really tap into its power I suggest reading up on Using Custom Assemblies with Reports & Extending Reporting Services.
You might also want to consider writing your own Custom Report Item, this lets you display anything you want in a highly efficient manner. Examples are the Dundas Add-ins, for Map, Calendar, Gauge, Charts, Other have written Barcode generators. See Readme_Custom Report Item Sample & the Reporting Services code samples (they shipped with the product in 2005 & are downloadable from Codeplex in SQL2008 Microsoft SQL Server Community Projects & Samples. You can also use an XSLT or other XML manipulation techniques to modify the Report Definition Language (RDL) as it is just XML constrained by a well documented schema.
1. Using a Report Expression.
Nearly every property of any report can be controlled using Report Expressions. They are the basic building block for the rest of this article.
How do you use one?
This sample will show how to display negative numbers as Red & in Brackets ie ($ -20.00)
Step 1: Open the Properties window. (If it isn’t visible, hit F4)
Step 2: Click the item (ie: textbox, table, chart) you want to modify.
Step 3: Select the Property you'd like to control.
First we need to change the Format property.Step 4: Select the <Expression...> option
Step 5: Set the Format property to: $ #,##0.00;($ -#,##0.00);Zero
- This can have 3 groups separated by semicolons. The 1st Group is for Positive values, The 2nd Group for negative & the last for the Zero Value.
- Formats use the very powerful .NET Formatting strings. See .NET Format String 101 & .NET Format String 102: DateTime Format String for a nice summary or the MSDN Reference Formatting Overview.
- TIP: Unlike COBOL you do not need to specify groups of 3 numbers. Putting a Comma between two "#" chars will comma separate groups of 3 numbers. Also makes it easy to Round to the nearest Thousand or Million. Just terminate the string with commas. Eg: "$#, K" will round to the nearest thousand & put the letter K on the end. “$#,,” will remove the left most 6 digits (for Millions) & so on. This is really handy when you are charting big numbers & don’t want lots of zeros in the Y axis labels.
Step 6: Set the Color Property to: =iif( Fields!myField.Value < 0, “Red”, “Black”)
The Result: This should display as.
WARNING: This example may be a “Worst Practice”. If you care about International Audiences, you should take advantage of SSRS’s use of the default .NET settings. It looks at the culture settings on the client computer & renders appropriately. Eg: Many Europeans prefer a comma as a decimal point & use a period to separate the Thousands. But be careful of this "Internationalisation" assistance, especially with currency amounts. You may need to guard against a change in the Dollar sign. If the currency really does represent an amount in dollars just swapping the Dollar sign to a Yen or Pound symbol is a very inaccurate way to do foreign currency conversion.
Handy Report Expressions
The SQL Books Online team did a good job at collecting many of the really useful report tips. See this article Using Expressions (Reporting Services) & use index to grab nearby articles. Also Bob Meyer's Blog Using RDL expressions in Report Builder
Tip 1: It is possible to display multiple distinct fields in one cell (textbox).
To display a date range "12:45 AM - 3:34 PM" Set the Value Property to
=FORMAT(Fields!StartDate.Value, "t") & " – " & FORMAT(Fields!EndDate.Value,"t")
If you provide formatting instructions as part of the Value Property, you don't need to set the Format PropertyTip 2: It is possible to use the value of one textbox as part of a calculation in another.
To refer to another TextBox use the prefix "ReportItems! " collection, this lets you refer to its value.
eg: If TextBox3 was "YOY Delta" with Value: "= Fields!2008Sales.Value - Fields!2007Sales.Value" then rather than Textbox4 "YOY Change" being "= (Fields!2008Sales.Value - Fields!2007Sales.Value) / Fields!2007Sales.Value".
You can reuse the calculation like:
"=ReportItems! textbox3.Value / Fields!Sales2007.Value"NB: Be careful with not to get too complex in your use of this. If you have a huge number of fields dependant on fields, that depend on other fields, with partial calculations combining multiple other fields etc. You should test this carefully as the calculation order is not guaranteed. If your cross report references change scope or aren’t yet calculated at the time your cell property is being calculated. You might not get the answers you expect.
Tip 3: Avoid "Divide by Zero Errors", but only check the denominator.
In the above example "=ReportItems! textbox3.Value / Fields!Sales2007.Value", if I had zero sales in 2007, I'll see "NaN" (Not a Number) or "Infinity". This expression would be better written to include a test to ensure I do not attempt to divide by zero ie: =iif( Fields!Sales2007.Value <> 0, ReportItems!textbox88.Value / Fields!Sales2007.Value , ""). I often see some very creative formulas that attempt to create the divide by zero error in the test & then provide a different result. eg: =iif( iserror(value/0), "-", value/0) this is a very sub-optimal approach & quite unnecessary.
Note: The above test works fine even if the denominator is NULL. Most .NET datatypes do not handle tri-state logic (True, False, Unknown), so NULL's are converted to 0 in most calculations.
Simple Conditional Coloring
Tip 2b: It is possible to use the value of one textbox to control the color of another.
In Part 2 of this "How to" guide you will see many different code alternatives that change the background color of a textbox. Remember the value you pass as a parameter doesn't have to be the value of the current text box. This is handy for flagging errors. eg: One manufacturer I worked with had a machine that created & packed 7 items at a time. They had a business rule that permitted a Sales Rep to give up to 20% discount if the order quantity was divisible by 7. If not, the max discount was 12%, as humans would need to unpack & repack the order.Option 1: Nested IF statements
=iif( (Fields!Discount.Value <= 0.12), "Green", ( iif(Fields!Discount.Value > 0.2, "Red", iif(Fields!Qty.Value mod 7 = 0, "Yellow", "Red") ) ) )Option 2: Switch Statement
=Switch( (Fields!Discount.Value <= 0.12), "Green", Fields!Discount.Value > 0.2, "Red", Fields!Qty.Value mod 7 = 0, "Yellow", true, "Red" )
This consists of multiple pairs of values each separated by a comma. The first value in the pair is a Boolean expression, the second value is what will be returned if the boolean is true. Each pair is evaluated left to right. Evaluation stops at the first pair that returns true. To simulate an "ELSE" clause ensure that the last pair always evaluates to true. Some people use "1=1" but I prefer to simply put "true",
2. Using a Custom Code
As powerful as Report Expressions are, they become inadequate if you require many lines of code or the same code is called from many different places within the same report. Even though the tool lets you enter vast amounts of code, its not something I’d recommend. You will create a maintenance nightmare. I’ve found that if it is more than a few lines of code, you will probably use it in other areas of your report. So it is cleaner to put it in one location & call it. This location is called Custom Code. SQL Books Online has good coverage on this see Using Custom Code References in Expressions (Reporting Services)
Steps to using Custom Code:
Step 1. Create your functions in the Custom Code window.
Step 1a. Click on the “Report” Menu, “Report Properties” submenu.
Note: This menu is context sensitive. In SQL2008, the Design Tab should have focus. In SQL2005 either the Data or Layout tabs need to have focus.
If the Preview Tab is selected you will have problems. The “Report Properties” submenu will be disabled <see graphic below>If you are in Edit Mode for one of the Report Items, the entire “Report” menu will not be visible. Hit enter to finish editing the property that has focus & it should reappear.
Step 1b. Select the Code Tab & enter or paste your code.
Tip: Only Public Functions can be called from Report expressions. Any private functions are only visible to other Functions within the window. You can create module level variables to share state &/or be constants. You can’t use the IMPORTS statement, but if you add a reference correctly it seems to create it for you.
Tip: You will rapidly discover this dialog is nothing more than a Multi-Line TextBox. It is far from an ideal development environment, but does the job. For anything decent, I open a separate VB.NET code project & write my code there, I also do my preliminary testing by passing static values to it. Once it is stable then I paste it into the code window. For smaller routines, I’ve developed them as Report Expressions, then lifted them out & turned them into a function.
Obvious tip: The Report properties dialog is resizable. It starts off quite small. I only mention to save embarrassment when you complain about coding thru a letterbox & someone asks “why didn’t you don’t drag it bigger?”.
Step 2. Use it from within your report expressions.
All your public functions are made available in a Code collection. To refer to a public function, just prefix it with the word “Code.”,
eg: =code.ColorRYG( Fields!Number.Value, 0, 255, 127)
Of course it can be used anywhere a function can be used & combined in any way you see fit.
eg: =4 / sin( code. myFunction(Fields!myfield.value) )
Custom Code example - selecting colors from a preset list.
If you had a field that with values from 1 to n. Perhaps you could use a report expression to map between it (ie: RegionID) and a color to display. eg:
=Choose(Fields!RegionID.Value, "Brown", "Blue", "GoldenRod", "Olive", "MediumTurquoise","Red", "Green", "DeepSkyBlue", "Yellow", "Chocolate", "Purple", "DarkOrange")
NB: If (Value <= 0) or (Value > number of items in the array), the color returned is "Transparent"
If RegionID was 2 then it would return “Blue”.
But often you just have a string value, ie: RegionName. So you could use Switch statement to create “Value – Color” pairs.
=Switch("Africa", "Brown", "Americas", "Blue", "ANZ","GoldenRod", "Asia","Olive", "Europe","MediumTurquoise", True, "Red")
The problem with that is readability & reuse. Many people prefer each pair to be spaced out on a separate line. So the custom code alternative would be.
Step 1: Paste this into the Custom Code window.
Public Function ColorRegion(ByVal RegionName As String) As String
Select Case RegionName
Case"Africa"
Return"Brown"
Case"Americas"
Return"Blue"
Case"ANZ"
Return"GoldenRod"
Case"Asia"
Return"Olive"
Case"Europe"
Return"MediumTurquoise"
Case Else
Return"Red"
End Select
End FunctionStep 2: Use it in a report Expression to assign a value to a Backcolor property.
=code.ColorRegion(Fields!Region.Value)
3. Using a other .NET Classes in your Custom Code
If you want to call .NET classes other than the ones exposed by default you will need to create a reference to them. The graphics below are from SQL2005. The dialogs in SQL2008 are similar, but slightly nicer to use.
Step 1: Click the “References” Tab.
Step 2. Click the “…” button & Use the Add a reference dialog to select the libraries you want.
This is exactly the same process you do if you add your own custom assembly.Reporting services preregisters the VB Library, System.Maths & System.Convert libraries. Using using additional .NET classes can be handy. Beware, most of the Report element properties just need a string or numeric value. So if you return some special object eg: a System.Drawing.Color object to a Color or BackColor property, it is an error. The Color property takes text representing a color name or RGB “0xFFFFFF” format.
So this is mainly useful if you want some more powerful processing within your function, perhaps using Regex for complex String manipulation or Matrix Transforms.
4. Using a Custom Assemblies
Just as Custom code lets you reuse your “special” routines in many data elements within the same report. It too can be criticised in the same way. The same code sprayed throughout multiple reports could become a maintenance issue. So if your report authors all start using the code examples I’ve provided below, consider compiling them into a .NET assembly & calling that from your reports.
The benefit is that the assembly code then be incorporated into your application lifecycle management (ie Source code control, bug tracking etc). Just by deploying a new version of your assembly enhancements can be quickly incorporated into all relevant production reports.
The downside to this is you need to deploy an assembly onto a production server. Not a problem if you own the server or can tell central IT what to do, more likely to be an issue if you are but a humble Report Author stuck at the wrong end of an MIS fiefdom.
To do this, see these sections of SQL Books Online
Appendix: Getting yourself started.
If you don’t have a suitable datasource & want to quickly try the functions provided in this article. Below is a query you can just paste into your datasource
Step 1: Create a Dataset.
If you have none, then cut/paste this into the TSQL area of your data set. As this is completely self-contained, it should work on any SQL Server you have permission to access.
Step 1a: Create a Data Source.
If you have SQL installed on your machine, set Server = “.” or “.\Instance name”
Set the database of the connection to any DB including master as it will not affect the database.
Step 1a: Create a Data Query.
Change the mod values in the WHERE clause to get more or less numbers.
Do some algebra in the Select List if you want a different range of values. eg: SELECT Number, (Number –128) * 10 as NegNumber FROM …
-- Brute Force approach to creating sequential numbers. -- But hopefully avoids distracting anyone not comfortable with TSQL. SELECT Number FROM ( SELECT 0 AS Number UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15 UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19 UNION ALL SELECT 20 UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23 UNION ALL SELECT 24 UNION ALL SELECT 25 UNION ALL SELECT 26 UNION ALL SELECT 27 UNION ALL SELECT 28 UNION ALL SELECT 29 UNION ALL SELECT 30 UNION ALL SELECT 31 UNION ALL SELECT 32 UNION ALL SELECT 33 UNION ALL SELECT 34 UNION ALL SELECT 35 UNION ALL SELECT 36 UNION ALL SELECT 37 UNION ALL SELECT 38 UNION ALL SELECT 39 UNION ALL SELECT 40 UNION ALL SELECT 41 UNION ALL SELECT 42 UNION ALL SELECT 43 UNION ALL SELECT 44 UNION ALL SELECT 45 UNION ALL SELECT 46 UNION ALL SELECT 47 UNION ALL SELECT 48 UNION ALL SELECT 49 UNION ALL SELECT 50 UNION ALL SELECT 51 UNION ALL SELECT 52 UNION ALL SELECT 53 UNION ALL SELECT 54 UNION ALL SELECT 55 UNION ALL SELECT 56 UNION ALL SELECT 57 UNION ALL SELECT 58 UNION ALL SELECT 59 UNION ALL SELECT 60 UNION ALL SELECT 61 UNION ALL SELECT 62 UNION ALL SELECT 63 UNION ALL SELECT 64 UNION ALL SELECT 65 UNION ALL SELECT 66 UNION ALL SELECT 67 UNION ALL SELECT 68 UNION ALL SELECT 69 UNION ALL SELECT 70 UNION ALL SELECT 71 UNION ALL SELECT 72 UNION ALL SELECT 73 UNION ALL SELECT 74 UNION ALL SELECT 75 UNION ALL SELECT 76 UNION ALL SELECT 77 UNION ALL SELECT 78 UNION ALL SELECT 79 UNION ALL SELECT 80 UNION ALL SELECT 81 UNION ALL SELECT 82 UNION ALL SELECT 83 UNION ALL SELECT 84 UNION ALL SELECT 85 UNION ALL SELECT 86 UNION ALL SELECT 87 UNION ALL SELECT 88 UNION ALL SELECT 89 UNION ALL SELECT 90 UNION ALL SELECT 91 UNION ALL SELECT 92 UNION ALL SELECT 93 UNION ALL SELECT 94 UNION ALL SELECT 95 UNION ALL SELECT 96 UNION ALL SELECT 97 UNION ALL SELECT 98 UNION ALL SELECT 99 UNION ALL SELECT 100 UNION ALL SELECT 101 UNION ALL SELECT 102 UNION ALL SELECT 103 UNION ALL SELECT 104 UNION ALL SELECT 105 UNION ALL SELECT 106 UNION ALL SELECT 107 UNION ALL SELECT 108 UNION ALL SELECT 109 UNION ALL SELECT 110 UNION ALL SELECT 111 UNION ALL SELECT 112 UNION ALL SELECT 113 UNION ALL SELECT 114 UNION ALL SELECT 115 UNION ALL SELECT 116 UNION ALL SELECT 117 UNION ALL SELECT 118 UNION ALL SELECT 119 UNION ALL SELECT 120 UNION ALL SELECT 121 UNION ALL SELECT 122 UNION ALL SELECT 123 UNION ALL SELECT 124 UNION ALL SELECT 125 UNION ALL SELECT 126 UNION ALL SELECT 127 UNION ALL SELECT 128 UNION ALL SELECT 129 UNION ALL SELECT 130 UNION ALL SELECT 131 UNION ALL SELECT 132 UNION ALL SELECT 133 UNION ALL SELECT 134 UNION ALL SELECT 135 UNION ALL SELECT 136 UNION ALL SELECT 137 UNION ALL SELECT 138 UNION ALL SELECT 139 UNION ALL SELECT 140 UNION ALL SELECT 141 UNION ALL SELECT 142 UNION ALL SELECT 143 UNION ALL SELECT 144 UNION ALL SELECT 145 UNION ALL SELECT 146 UNION ALL SELECT 147 UNION ALL SELECT 148 UNION ALL SELECT 149 UNION ALL SELECT 150 UNION ALL SELECT 151 UNION ALL SELECT 152 UNION ALL SELECT 153 UNION ALL SELECT 154 UNION ALL SELECT 155 UNION ALL SELECT 156 UNION ALL SELECT 157 UNION ALL SELECT 158 UNION ALL SELECT 159 UNION ALL SELECT 160 UNION ALL SELECT 161 UNION ALL SELECT 162 UNION ALL SELECT 163 UNION ALL SELECT 164 UNION ALL SELECT 165 UNION ALL SELECT 166 UNION ALL SELECT 167 UNION ALL SELECT 168 UNION ALL SELECT 169 UNION ALL SELECT 170 UNION ALL SELECT 171 UNION ALL SELECT 172 UNION ALL SELECT 173 UNION ALL SELECT 174 UNION ALL SELECT 175 UNION ALL SELECT 176 UNION ALL SELECT 177 UNION ALL SELECT 178 UNION ALL SELECT 179 UNION ALL SELECT 180 UNION ALL SELECT 181 UNION ALL SELECT 182 UNION ALL SELECT 183 UNION ALL SELECT 184 UNION ALL SELECT 185 UNION ALL SELECT 186 UNION ALL SELECT 187 UNION ALL SELECT 188 UNION ALL SELECT 189 UNION ALL SELECT 190 UNION ALL SELECT 191 UNION ALL SELECT 192 UNION ALL SELECT 193 UNION ALL SELECT 194 UNION ALL SELECT 195 UNION ALL SELECT 196 UNION ALL SELECT 197 UNION ALL SELECT 198 UNION ALL SELECT 199 UNION ALL SELECT 200 UNION ALL SELECT 201 UNION ALL SELECT 202 UNION ALL SELECT 203 UNION ALL SELECT 204 UNION ALL SELECT 205 UNION ALL SELECT 206 UNION ALL SELECT 207 UNION ALL SELECT 208 UNION ALL SELECT 209 UNION ALL SELECT 210 UNION ALL SELECT 211 UNION ALL SELECT 212 UNION ALL SELECT 213 UNION ALL SELECT 214 UNION ALL SELECT 215 UNION ALL SELECT 216 UNION ALL SELECT 217 UNION ALL SELECT 218 UNION ALL SELECT 219 UNION ALL SELECT 220 UNION ALL SELECT 221 UNION ALL SELECT 222 UNION ALL SELECT 223 UNION ALL SELECT 224 UNION ALL SELECT 225 UNION ALL SELECT 226 UNION ALL SELECT 227 UNION ALL SELECT 228 UNION ALL SELECT 229 UNION ALL SELECT 230 UNION ALL SELECT 231 UNION ALL SELECT 232 UNION ALL SELECT 233 UNION ALL SELECT 234 UNION ALL SELECT 235 UNION ALL SELECT 236 UNION ALL SELECT 237 UNION ALL SELECT 238 UNION ALL SELECT 239 UNION ALL SELECT 240 UNION ALL SELECT 241 UNION ALL SELECT 242 UNION ALL SELECT 243 UNION ALL SELECT 244 UNION ALL SELECT 245 UNION ALL SELECT 246 UNION ALL SELECT 247 UNION ALL SELECT 248 UNION ALL SELECT 249 UNION ALL SELECT 250 UNION ALL SELECT 251 UNION ALL SELECT 252 UNION ALL SELECT 253 UNION ALL SELECT 254 UNION ALL SELECT 255 UNION ALL SELECT 256 ) AS Numbers WHERE (Number % 5 = 0)
Of course if you just want to load a lot of rows into a Table & then select from it, try something simpler , but change the select into an Insert into your table.
DECLARE @iCount INT SET @iCount = 0 WHILE @iCount < 256 BEGIN SELECT @iCount as Number; SET @iCount = @iCount + 1 END
If you are using SQL2008, don’t overlook the new code enhancements. Declare & Set in one statement, & the “+=” operator.
DECLARE @iCount INT = 0; WHILE @iCount < 256 BEGIN SELECT @iCount as Number; SET @iCount += 1; END
Please give feedback. Is this series of articles useful? Did it save you time? What was good, What could be better?, Notice any errors? What would you like me to cover? All thoughts, comments, suggestions welcome.
Technorati Tags: SQL Server 2008,SQL 2008,SQL Reporting Services,SQL Server 2005,SQL 2005,SSRS,Color Coding,Colour Coding,Conditional Formating,Charts,Graphs
Comments
Anonymous
February 16, 2009
This "How to" guide provides ideas & code samples on using color to improve your users understandingAnonymous
February 16, 2009
Part 4 of 4: Continuous Color functions for Multi-Dimensional analysis (in charts) This "How to" guideAnonymous
February 16, 2009
This "How to" guide provides ideas & code samples on using color to improve your usersAnonymous
February 16, 2009
wow i say!! David Lean has just released an in depth, 4 part series on how to use conditional formattingAnonymous
February 19, 2009
I recently helped my Australian colleague David Lean successfully resolve a small report design challengeAnonymous
February 20, 2009
The comment has been removedAnonymous
February 22, 2009
The comment has been removedAnonymous
May 03, 2009
Excellent post! However, in Tip 3, using a single IIf() might not always avoid the divide by zero error. If the denominator comes from certain database data types (eg. money or decimal) then the single IIf() would still cause an error. You need to use something described in this post: http://blogs.msdn.com/bwelcker/archive/2006/09/26/End-of-Amnesia-2800_Avoiding-Divide-By-Zero-Errors_2900.aspxAnonymous
March 20, 2012
Great post for conditional formatting!! If I export a report to Excel, how can I get the conditional formatting to export/transform into Excel conditional formatting?Anonymous
June 25, 2012
devdex.wordpress.com/.../sql-server-reportingapply-checks-on-report-fieldsAnonymous
April 08, 2013
Nice blog,But can you explore also how to highlight color for text onlyAnonymous
November 01, 2013
Useful article !!Anonymous
March 27, 2014
Hi Is there a way to format based on 2 fields.. i.e a And Condition clause where i check values on 2 fields and then do fromating .. i,e if a > f00 and b.contains('string') then color1 else another conditionAnonymous
August 12, 2014
Very helpful aticle. But how about the report performance for the conditional formatting?Anonymous
March 31, 2015
How would I be able to achieve conditional cell colouring with a formula like : =iif(IsNothing(this),"Red","") this referring to the current cell value, without having to name the dataset column.Anonymous
September 14, 2015
Hi I need help in this code - I want to use 1 field to filter and the second field must be displayed -- but I get an error ? Herewith what I have : Function HotelOther(ByVal Product_Desc_Review as String),(ByVal Product_Description as String) as String IF Product_Desc_Review ="Hotel" then return Product_Description IF Product_Desc_Review ="Misc" then return Product_Description End Function