Welcome to MSDN Blogs Sign in | Join | Help

More FREE training for Developers & DBA’s

I tend to forget about this little gem, so this post more of a reminder to me, that I hope you will find handy too.

Ramp Up: eLearning Site

Official News

I’m happy to announce that we’ve just launched 3 brand new learning tracks on Ramp Up* (www.MyRampUp.com):

  1. Web Development with ASP.NET
  2. Move from ASP to ASP.NET
  3. Move from PHP to ASP.NET

Official Description

Ramp Up (www.MyRampUp.com) is a free online learning program for developers. We’ve just launched three ASP.NET tracks: “Web Development with ASP.NET”, “Move from ASP to ASP.NET”, and “Move from PHP to ASP.NET”. These tracks, along with the other currently offered ones (eg, Windows Mobile 6, SharePoint for Developers, Visual Studio 2008), teaches the important skills in a guided path, making the learning process easier and more efficient. The easy-to-access content (provided by subject-matter gurus) is specifically tailored for the Ramp Up program, and offered in a variety of forms (article, v-lab, codecast and slidecast). Check them out now at www.MyRampUp.com, and see how Ramp Up can help you become more employable by learning important and marketable skills.

My 2 cents thoughts

MyRampUp is a page off the MSDN.Microsoft site. It takes you to the Microsoft Learning site which is an aggregate site for all kinds of learning styles. It lets you filter by topic & lists; Textbooks, e-Learning & other courses. If you are looking for something online & free, click over on the Right Margin “Free Products”. You do need to register, it cost you nothing, & it lets you create your own training plan, which you add courses that take your fancy & tick them off when you’ve completed them.

Other related sites definitely worth a look

Enjoy
    Dave

Thought for the day: Some people make it happen, Some people watch it happen, & some people ask “What happened?”

Technorati Tags: ,,

News: Look at the CTP3 of our upcoming Distributed Cache technology - Velocity

If you develop high scale, scale out/distributed apps, check out

Microsoft Project Code Named “Velocity” Community Technology Preview 3 (CTP3) Released to Web on 7 April 09.

"Velocity" is a distributed in-memory application cache platform for developing scalable, high-performance applications. "Velocity" can be used to cache any common language runtime (CLR) object and provides access through simple APIs. The key aspects of "Velocity" are distributed cache performance, scalability, and availability.

This release contains several security and performance enhancements, as well as the new cache notifications feature which allows clients to be notified when changes are made at either the key, region, or cache level. In addition, it also includes numerous refactorings to its API, making it more conformant to the .NET Framework guidelines as well as easier to consume. “Velocity” is currently slated for release in the middle of this year and will represent an integral piece of our overall web/data story.
When complete it will be part of the .NET platform, ie: Free

 

Posted by davele | 2 Comments
Filed under: , ,

Get SQL Server 2008 for FREE: FREE Database, FREE Reporting Solution, FREE Spatial

If you are a Student, Teacher or anyone on a budget, don’t feel pushed to use Open Source databases like MySQL just because they have an entry level offering for free. You may be one of many who expressed concern for its quality & design which suffered when SUN purchased MySQL. Who knows what will happen now that Oracle are trying to buy SUN. Take the time to compare it feature for feature to SQL Server you will find it is missing a lot.

Microsoft makes a lot of its software available for free to anyone. In addition, many groups like Primary, High & Unit Students, Teachers, Start-Up Business’s & Microsoft technology partners can qualify for even more free stuff (for some groups we give them every product we produce). See my blog post How do I get FREE stuff from Microsoft?

 

So, it is possible for anyone to get the SQL Server 2008 database for FREE. This includes the Spatial capability, some Replication, Integration, Auditing & Management capability.
It is also possible for anyone to get SQL 2008’s Reporting Services for FREE too. (either as part of SQL Express, or using the Report Viewer Control that ships with Visual Studio). 

 

You can do this by downloading any one of the SQL 2008 Express packaging below. For more details on what Express has, see SQL Server 2008 Express
If you have SQL Workgroup thru to SQL Enterprise don’t use the Express Service pack 1 (below). See this post SQL Server 2008 Service Pack 1 instead.

As part of the recent April 2009 releases mentioned in my blog: SQL Server 2008: April 09 Updates – Handy Links SQL Server 2008 Express was also updated.

Where do I get it? (Available FREE to Everyone)

SQL Server 2008 Express, is a very powerful, full featured database engine. It is compiled from the same source code tree as the Enterprise edition. Any applications that you develop for it will also run exactly the same on any of the other editions; Workgroup, Standard, Enterprise, Developer or Web. ie: “bug for bug compatibility”

The Express edition has been limited in some areas. To compare it to the more fully featured editions see SQL 2008 Compare Edition Features (NB: Remember to expand the “Plus Signs”). But in summary:  It will only use 1 physical processor (could be a quad proc, so not a big limitation). It’s databases are limited to 4Gb. This is actually a lot of data, especially when you consider you can have 1,000’s of databases per instance & 16 Instances per server. So 4TB * 16 Instances. But clearly spraying ove so many database; your CPU, backup strategies &/or distributed schema would become an issue.
If you find that constraining, the upgrade path is to detach the database & attach it to SQL 2008 Workgroup. It costs ~$1,000, limited to 2 Physical CPU’s (Quad Core = 8 CPU’s) & 50GB databases. Or just go straight to Standard or Enterprise editions.

7 April 09 Microsoft SQL Server 2008 Express Edition Service Pack 1

Update to any release of SQL 2008 Express

20 Feb 09  Microsoft SQL Server 2008 Management Studio Express

This is a definite download if you aren’t able to get your hands on the Management tools that ship with SQL Developer/Enterprise/Standard Editions.
 

22 Feb 08 Microsoft SQL Server 2008 Express with Advanced Services

SQL Server Express that includes a graphical management tool, and powerful features for reporting (Reporting Services) and advanced text-based searches.

8 Feb 09  Microsoft SQL Server 2008 Express with Tools

Free SQL Server Express that includes graphical management tools. Same database, just smaller install package, with no Reporting to install.


You can also get SQL Server Compact v3.5 (aka SQL Mobile Edition) this is highly optimised for a single user, with a focus on minimising its memory & disk footprint. Great for distributed solutions. The TSQL you write for it, also works on the other SQL 2008 editions. But be aware it is a subset of the language features of the SQL 2008 Editions.

6 Aug 08 Microsoft SQL Server Compact 3.5 Service Pack 1 for Windows Mobile

Service Pack for SQL on Mobile Phones, PDA’s & Laptops (if you want)

How do I get FREE Software from Microsoft?

It is common to hear students & small start-up businesses state “I use Open Source because it is free” or they download pirate Microsoft from really dodgy, spyware prone sites to get it free.

The irony is that many of these people qualify to get the software for FREE or at least heavily discounted prices but they don’t know to ask.

The following post highlights a few of the ways this is possible.

Important: Offer expires 30 June 2009;
Be a qualified “Microsoft Certified Professional” If you are a student, Microsoft will pay the cost of your MS Certification exams. See “Boost your resume” below.

 

Everyone

Online Education for Developers

Channel 9

Online Education for Infrastructure Folks (IT Professionals)

 TechNet Edge

 

For Students & Teachers - DreamSpark

DreamSpark is a program set up by Microsoft to provide students with software design and development tools at no charge. Click here for full details.

Note to Teachers: This is professional grade s/w, your students will use when they leave school. No need to suffer trying to teach with really old or shareware s/w. Nor do you need to try to teach with desktop s/w that works ok on the Mac but your kids don’t have it at home. The wizards make it easy to learn. It is brilliant for teaching IT & relevant to nearly all high school IT curriculum. (I know because my kids attend High School & study IT)

 

What sort of s/w can I get for free?

  • Visual Studio 2008 Professional Edition (Windows & Web, VB, C#)
  • Microsoft Expression Studio 2  (includes great graphic design tool, also powerful web design tool)
  • SQL Server 2008 Developer Edition (this is everything that ships in the Enterprise Edition)
  • Windows Server 2008 Standard
  • Robotics Developer Studio 2008
  • Xna Game Studio 3.0
  • + more

Is there a catch?
YES. Your Education institution has to validate that you are a student. In Australia, I’m told all Universities are connected & you can validate quickly via the Web site.

For School students. The process is made more complex in order to ensure the privacy of the children. The school needs to ask Microsoft for a set of keys. The school distributes the keys to its students. The student can then use the key to anonymously download any of the s/w they are interested in.
If you are a High/Primary School Student please ask your teacher for a code. If they don’t know, point them at the link below.

If you are a Primary / High School Teacher & want to register your school, Click here

 


Boost your resume, get a recognised Microsoft Certification FOR FREE.

Click here => Microsoft will pay for your Technical Specialist exams for any student that registers & take the exam(s) before 30th June 2009.


Australian State Education Departments

What about the other products that aren’t S/W design & Development?

Most of the Australian Dept’s of Education have signed agreements with Microsoft to provide Server & Desktop tools to all the schools.
My perception is that this is broken. The Dept appears to make the s/w available to the schools who request it. The NSW Teachers that I’ve talked to don’t know to ask for the s/w. So they don’t get it & have to make do, when they could have great solutions. As a parent, this frustrates me. I don’t know how well this process is working in the other states.

 

Online Education for Students

 

 

For Start-up Businesses – BizSpark Program

This has to be the sweetest deal I’ve seen … ever. Get Hundreds of Thousands of dollars worth of s/w. Get Access to people who can help sell your product, mentor you &/or assist with business advice. All just for signing up..

If you :-

  • are starting or started your business in the past 3 years,
  • actively engaged in development of a software-based product or service
  • generate less than us$1Million

You might qualify to be included in the BizSpark program. BizSpark Overview Microsoft provides nearly all of our products & a lot of support (technical & business) to help new companies get over the challenges of those early years getting a product to market. How does it work?


To see if you qualify click Do I qualify?

For a list of s/w. click What s/w do I get? 
Note that in addition to the huge list of high end server products, including Team Suite versions of the dev tools, you also get an MSDN Premium subscription. This supplies you with just about every product Microsoft makes, excluding games & H/W.

To get started, click Web based Signup Agreement

For new IT Related businesses – Empower for ISV’s

Click here => Microsoft Empower for ISVs is an initiative for independent software vendors creating new software solutions using Microsoft® technology. Membership gives you access to essential development tools, resources, and support that will help you accelerate your product development and get your application to market faster.  This program costs ~ us$375 per year.

Do I qualify?

Requirements for Microsoft Empower for ISVs
To take advantage of the valuable Empower initiative, your software development company must commit to developing one packaged and resalable custom application that supports at least one of the following Microsoft technologies:

  • Windows Vista® operating system
  • 2007 Microsoft Office system
  • Windows Server® 2008 or Windows Server 2003
  • Microsoft SQL Server® 2008 or SQL Server 2005
  • Microsoft Dynamics™ business management solutions
  • Windows Mobile software

Does Your Software Development Company Qualify?
The great benefits of Microsoft Empower for ISVs are available to any micro, small, or medium independent software development company in an intense building phase.

What Do I get?

MSDN Premium Subscription with 5 Dev & Testing Licenses

The full range of Microsoft integrated server software; all Microsoft operating systems; Microsoft productivity applications including: Microsoft Office Professional 2007, Microsoft Office Project Professional 2007, Microsoft Office Visio® 2007 drawing and diagramming software, and Microsoft MapPoint® 2009 business mapping software.

Up to 5 internal-use software licenses for:

  • Microsoft Visual Studio® 2008 Professional Edition
  • Windows Vista® Business Operating System
  • 2007 Microsoft Office System or Microsoft Office Professional 2007

One software license and up to 5 CALs for:

  • Windows Server 2008 Standard or Enterprise
  • Exchange Server 2007 Standard or Enterprise Edition
  • SQL Server 2008 Standard or Enterprise Edition
  • Office SharePoint Server 2007 Standard or Enterprise CAL

Technical Advisory Services
10 hrs of phone-based professional consulting. Select from a broad range of services, including:

    • Software development advice
    • Best-practice recommendations
    • Code samples
    • Limited technology-, architecture-, or application-
      design review

Innovate On
Training, code samples, logo certification, and go-to-market opportunities to help you complete your development process and market your solution effectively.

For Existing IT Businesses – Certified Partner Program

Who is it for?

The Microsoft Partner Program is designed for all partners who develop and market solutions based on Microsoft platforms, provide consulting or technical services on Microsoft systems, or recommend Microsoft technology purchases. Click here for details.


I will not repeat the web site here, but in summary.

There are 3 levels; Registered, Certified & Gold Certified.

Cost to join: Registered costs nothing, Certified & Gold Certified cost $3465 per site if you qualify.

This gives you access to heavily subsidised s/w. In the case of Gold Certified, Hundreds of Thousands of dollars in s/w you can use for internal staff, development, demos for your sales / consulting people etc.

 

This is not a complete list. But it is now 2am, I know I’ve missed something big but can’t recall what it is.

I hope this helps you to better tap into the vast array of free stuff. Thanks for reading this far.

Dave

SQL Server 2008: April 09 Updates – Handy links

Scanning the Microsoft sites it might not be obvious that April 09 was a huge month for new releases from the SQL Team. Given that it is sometimes difficult to find everything in one place I thought I’d make it easier for you by creating this index.

Beyond the links there is nothing in this post particularly insightful.

As mentioned in my prior news post SQL Server 2008 Service Pack 1 was released. In addition, lots of related stuff was updated.

Latest updates to the Interoperability & Extensions to SQL Server

 

7 April 09 Microsoft SQL Server 2008 Data Mining Add-ins for Microsoft Office 2007, April 2009

This is brilliant technology that makes Data Mining accessible to people who haven’t got a clue about Data Mining. Just need Office Excel 2007 & a copy of SQL 2008 Analysis Server, with the Data Mining Sessions parameter turned on & all your business users can mine the data they pulled into their Excel Spreadsheet. This delivers two add-ins for Microsoft Office Excel 2007 (Table Analysis Tools and Data Mining Client) and one add-in for Microsoft Office Visio 2007 (Data Mining Templates).

There is also a version that works for SQL 2005 & Office 2007. While not quite as full featured it is still very nifty. It is contained in the Feature Pack for SQL Server 2005 - February 2007 There is also a version for Office 2003 & SQL 2005, but I can’t find a link to it any more, so I assume we’ve pulled it.

7 April 09 Microsoft SQL Server 2008 Reporting Services Report Builder 2.0, April 2009

An intuitive report authoring environment for business and power users to create SQL Reporting Services Reports. This update now supports Click-Once Install.

7 April 09 Microsoft SQL Server 2008 Reporting Services Add-in for Microsoft SharePoint Technologies, April 2009

Display your reports natively inside SharePoint. Sure you can put SQL Reports into SharePoint without this add-in. But it provides much nicer integration, especially letting you control security using the SharePoint’s security on the page.

7 April 09 Microsoft SQL Server 2008 Upgrade Advisor, April 2009

When you install SQL 2008 on a machine which has previous editions of SQL installed, the SQL 08 setup program includes the Upgrade Advisor & will run this Upgrade check & warn you of any potential issues with your schema. Well…, it runs this if you are attempting to upgrade the existing instance. If you are just creating an additional SQL 2008 instance next to you previous versions there is nothing to check.

It is a good idea to download this first & scan your databases prior to attempting to setup over the top. At the same time you could use profiler to capture a representative sample of your applications queries & scan them too. This will give you a much more thorough check of your system & reduce the potential issues you may have upgrading your production systems.

Note: If you move your SQL 2000/2005 database to SQL 2008 & run it in compatibility mode. The Upgrade Advisor will not be able to scan it & you lose the ability to get any insight this tool may have provided you.

 

7 April 09 Microsoft SQL Server 2008 Feature Pack, April 2009

The Feature pack includes a large variety of other interoperability & other add-ins. Especially popular is the Microsoft SQL Server 2005 Driver for PHP This driver also works for SQL 2008. But note: Unlike the JDBC driver which has UNIX version, the PHP Driver only runs on Windows platforms.
Tip:  The feature pack points to the older JDBC Driver v1.2, use the JDBC v2.0 below.

Feature Pack for SQL Server 2005 - February 2007  perhaps you may find it handy, this is the equivalent for your SQL 2005 servers

 

3 April 09 Microsoft SQL Server JDBC Driver 2.0

a Type 4 JDBC driver that provides database connectivity through the standard JDBC application program interfaces (APIs) available in Java Platform, Enterprise Edition 5.

30 Jan 09 Microsoft SQL Server 2008 Books Online - Jan 2009

Always handy to be using the latest release of the docs, They constantly are adding more examples & better explanations.

I trust this saves you some time,

Dave

Teach your Kids to Program these school Holidays

If you know Primary, High School aged kids OR know a teacher who struggles to keep up with Technology. Point them at Kid's Corner.

This site is full of videos, articles, tips & tricks. Many of the videos are have young teens being actors & doing the voiceovers.

For some examples, check out a Kids' Corner Videos

There are some great materials & videos here to help people learn about programming & computers.

Yes, I did cringe when the ~15 yr instructor described VB as “a really old language that has been around since 1991”. It doesn’t seem that long ago when I was on the team planning its Aust launch. I guess COBOL-68, Algol & Ada, aren’t as popular now “as it was back in my day”.

 


Other tools that have proved educational & popular with my family.

  • Phrogram a VB like language with extra classes that makes it easy for 10+ years to create their own animated computer games.
  • Armadillo Run is a physics-based puzzle game. You have to build structures with the purpose of getting an armadillo to a certain point in space. There is a selection of building materials, each with different properties, which can be combined to form almost anything. The realistic physics simulation gives you the freedom to solve each level in many different ways.
  • My son just asked me to add “All the Age of Empire games”. Which I have to agree with, he is great at history. His interest started by playing the AoE games, reading the manual & learning the battle strengths of each civilisation. He then watched any Documentaries on SBS & History Channels. The same can’t be said for his siblings, who also played with 0 benefit.
  • Railroad Tycoon 1, 2 & 3. These games are brilliant for teaching basic commerce (Supply & Demand, Industry Location & Interdependency, Predatory Pricing), Economics (Interest Rates, Labour & Unemployment cycles) & Equities (Fund raising, Stock Splits, Bonds). Difficult to source but worth it if you kids get into it. NB: I’ve heard the latest game in the series “Sid Meier’s Railroads” is disappointing & lost much of the real world realism.

 

Quote for the day: When I started teaching my aspiration was to “Mold young Minds”, some days I’d be content just to “wack young heads”.

Free Chart Controls for .NET: Windows and Web – Handy Links

Even though its been available for more than 6 months, many people have overlooked this little gem. Those that are using it get terribly excited when they discover how easy it is to use the features & capability it offers. So if you need very powerful charts in your application, read on.
Below are a few samples of some of the more interesting things you can do. Currently a separate download for .NET v3.5, they will be included as part of .NET Framework 4.0.

Bands_MA Bollinger_2Charts_Dividends PieChart Ranges Histogram BoxPlot

Where do I get it?

Microsoft Chart Controls for Microsoft .NET Framework 3.5   Charts for both Web & also Windows Forms. Released 9 Aug 08 

Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008    Provides Intellisense & the Toolbox Designer. Released 16 Sep 08

Microsoft Chart Controls for .NET Framework Documentation  Remember to read at least the first bit of this as it points you to some great samples on Codeplex & the support forum. Released 14 Oct 08

If English isn’t your language of choice, there are 28 Language Packs to choose from Microsoft Chart Controls for Microsoft .NET Framework 3.5 Language Pack (of course the English one I linked to is lame as everything is in english by default so it doesn’t have anything insightful. But it is the only language I can read :-(

Is that it?

How do I get started?

  • Download Samples Environment for Microsoft Chart Controls from codeplex.  You will see an executable, WinFormsChartSamples.exe & a C# project that you creates it. Don’t waste your time looking for a VB.NET version. Just run the .EXE, it displays sample charts & the sample code you need to create that feature in both VB.NET & also C#.
  • For help you can post questions on the Chart Controls for .NET Framework forums on MSDN
  • Also a great read is Alex Gorev's Weblog Alex is the Microsoft Architect responsible for creating these controls. And has posted many useful tips.
  • And if you are new to C# or VB.NET there are Tutorials & other free stuff here Get Started with Visual Studio

 

Is there anything else I should know?

I heard these charts were part of the code Microsoft purchased from Dundas in April 07. What are the differences? See Alex Gorev's Blog: Microsoft Chart Control vs. Dundas Chart Control

What if I need “More Power!!”

This release of the charts were derived from the codebase equivalent to Dundas Charts v5.5. MS & Dundas folk continue to evolve the code. Dundas release new versions quite frequently. Their version 6 has some cool new capability. Currently they are in Beta for Version 7, Check it out here Dundas Chart for .NET 7 Beta Now Available They also have some other nice components including one targeted at OLAP.

Before you ask, YES over time MS will incorporate the capability of the newer releases in our products. I have been impressed by, & enjoy, the speed that Dundas innovates & introduces new capability into their product line. So why doesn’t Microsoft release new products at that frequency? Many reasons but a major one is that very few people want us to. As a developer I’m happy to update to the latest release of a chart control every 3-4 months. But like many, I wouldn’t be keen on updating to a new release of Windows, Office, SQL Server or even Visual Studio at that frequency. The effort to upgrade those systems is much greater,especially if I want all my dev environments to be identical & remain stable throughout a project.

 

Is this the only architecture I could choose?

    1. If you only need Charts in you Application or Web site  – go with this or the Dundas equivalent.
      Advantage: High-speed, interactive charts, tight integration with your apps UI.
    2. If you need to display both Charts and supporting Data consider using a Report. Either :-

      A.  Use the Reporting Services Report Viewer control that ships with Visual Studio 2005 & 2008. (FREE)
      Advantage(s):
      It can run in Local Mode (for disconnected experience) & Remote Mode (which lets you display reports generated by a SQL Reports Server.) This online/offline experience is done by changing the value of one property.
      The local reports are rendered really fast within the context of your app, so you can get a very interactive feel.
      Disadvantage:
      VS2008 shipped before SQL 2008 was released. So, in Local Mode, this control does not have the improved charts, gauges, Rich Text, Tablix & other niceties provided by SQL 2008 Reporting services. It is capable of displaying the newer SQL 2008 Reports when switched to Remote mode.  

      B.  Use SQL Server 2008 Express with Advanced Services. (FREE)
      This provides a copy of SQL 2008 Reporting Services to run on your machine.
      Advantage
      Even when you aren’t connected to a network, your reports can access all the new features in SQL 2008.
      Disadvantage:
      The data sources for your report are limited to those on that machine, even if you are connected to a network. Of course you can use the Report Viewer to connect to this version too. If you upgrade to SQL Standard or Enterprise this limitation is removed, they can use any data source, located anywhere.

I hope this improves your productivity. Dave.

SQL Server 2008 Jumpstart Materials – very detailed training, now FREE to download.

This post is a pointer to a lot of in-depth training on SQL 2008. It includes Virtual PC’s with Demo Scripts, Lab Exercises & a lot of PowerPoint's with notes.

To get access to it all click here SQL Server 2008 Training. It is free but you do need to register as helps us to cost justify developing this type of material.

 

What is it?

As SQL 2008 was being developed. The team at corp ran a number of workshops with the bigger S/W development companies (Independent S/W Vendors (ISV’s)). It was intended to help them optimise their product for the new platform & to expose them to the new features they may be able to use to gain a competitive advantage.

This material has a lot of very useful detail on the changes.

To help you decide if it is relevant to you, I’ve listed, below, the Sessions that we ran over several days.

 

Overview Sessions

0. SQLServer08 - Executive Update.pptx 
1. SQLServer08 - Data Platform Software + Services.pptx 
2. SQLServer08 - Mission Critical.pptx
3. SQLServer08 - Manageability.pptx 
4. SQLServer08 - Business Intelligence.pptx 
5. SQLServer08 - Next Generation Data Applications.pptx 


Database Infrastructure Track

DBIS Module 1 - Overview.pptx 
DBIS Module 2 - Availability Enhancements.pptx 
DBIS Module 3 - Security Enhancements.pptx 
DBIS Module 4 - Policy-based Management and Multi-server Administration.pptx 
DBIS Module 5 - Throttling and Troubleshooting.pptx 
DBIS Module 6 - Features To Manage Part 1.pptx 
DBIS Module 7 - Features To Manage Part 2.pptx 
DBIS Module 8 - Scalability Enhancements.pptx 
DBIS Module 9 - Query Optimizer Enhancements.pptx 
DBIS Module 10 - Performance Studio.pptx 
L01_SQL Server 2008 Using Policy-based Management.docx 
L02_SQL Server 2008 Using Performance Studio.docx 
L03_SQL Server 2008 Database Mirroring in Action.docx 
L04_SQL Server 2008 Peer to Peer Replication.doc


Business Intelligence Track

Part1_01 - Microsoft BI Strategy Overview .pptx 
Part1_02 - Intro Dimension Modeling Techniques.pptx 
Part1_03 - Intro To ETL.pptx 
Part1_04 - Intro To SSRS.pptx 
Part1_05 - Publishing and Accessing Reports.pptx 
Part1_06 - Intro To UDM.pptx 
Part1_07 - Accessing UDM.pptx 
Part1_08 - Intro To Data Mining.pptx 
Part1_09 - Building Dashboards.pptx


Part2_01 - Improving Integration.pptx 
Part2_02 - More Flexible Richer Reports.pptx 
Part2_03 - Using SSRS Management Tools.pptx 
Part2_04 - Leveraging SSRS Programmability.pptx 
Part2_05 - Accelerating SSAS.pptx 
Part2_06 - Managing SSAS.pptx 
Part2_07 - Understanding SSAS Queries.pptx 
Part2_08 - Data Mining.pptx 


Developer Track

01. Introduction.pptx 
02. TSQL.pptx 
03. Beyond Relational.pptx 
04. Service Broker.pptx 
05. SQLCLR.pptx 
06. Visual Studio.pptx 
07. Client Programmbility.pptx 
08. Entity Framework.pptx 
09. HTTP Programming.pptx 
10. OCS.pptx 
L01_SpatialLabsInstructions.docx 
L02_DatabaseClients.docx 
Dev Track Scripts.zip 


Upgrade Track

00. Opening And Welcome.pptx
01. Upgrade Technical Value Proposition.pptx
02. Anatomy Of An Upgrade.pptx
03. Upgrade Advisor.pptx
04. Application Compatibility Testing.pptx
05. Planning Your Upgrade.pptx
06. Hands On Lab.docx


SQL Server 2008 Demo

SQL Server 2008 Demo VPC - Release 2
SQL Server 2008 Presenter Script - Release 2.docx 


Hands-On Lab VPCs and Lab Manuals

There are TWO Hands-On Lab VPC and Lab Manual Collections:

COLLECTION 1: SQL Server 2008 HOLs which has 19 associated Lab Manuals, AND
COLLECTION 2: SQL2008AlwaysOnHOL which has 10 associated Lab Manuals and 1 Readme file

COLLECTION 1 - SQL Server 2008 Hands-On-Labs

Collection 1: SQL Server 2008 HOLs VPC Image


SQL Server 2008 HOLs VPC

Collection 1: SQL Server 2008 HOLs Lab Manuals
Data_Mining_withSS2008_HOL.doc 

Delivering_SSAS_Capabilities_Through_MSOffice_HOL.doc 
Partition_Processing_for_DW_HOL.doc 
Plan_Freezing_HOL.doc 
Resource_Governor_HOL.doc 
Spatial_Data_and_VE_HOL.doc 
Spatial_Data_HOL.doc 
SQL_Server_2008_ChangeDataCapture_HOL.doc 
SQL_Server_2008_DATETIME_Data_Type_HOL.doc 
SQL_Server_2008_TableValuedParameters_HOL.doc 
SQL_Server_2008_Using_Performance_Studio_HOL.docx 
SQL_Server_2008_Using_Policy-based_Management.docx 
SQL_Server_Compact_Building_Occasionally_Connected_SystemsHOL.docx 
SSAS_Designing_Analysis_Services_Solutions_HOL.doc 
SSAS_Managing_Analysis_Services_Solutions_HOL.doc 
SSRS_Authoring_Reports_Using_Reporting_Services_HOL.docx 
SSRS_Managing_the_Report_Services_Infrastructure_HOL.doc 
Transparent_Data_Encryption_HOL.doc 
What_Is_New_For_DBAs_in_SQL_Server_2008_HOL.doc 

COLLECTION 2 High Availability: SQL2008 AlwaysOn HOL


Collection 2: SQL2008AlwaysOnHOL VPC Image

SQL2008 AlwaysOn HOL VPC


Collection 2: SQL2008AlwaysOnHOL Lab Manuals
Data Recovery Preventative Techniques.doc 
Database Mirroring.doc 
Database Snapshots.doc 
Instant Initialization.doc 
Online Operations.doc 
Peer to Peer Replication.doc 
Service Oriented Database Architecture.doc 
Snapshot Isolation.doc 
Table and Index Partitioning.doc 
Transparent_Data_Encryption_HOL.doc 

Hope this is useful for you

Dave

SQL Server 2008 SP1 - Released

April 09: Service Pack 1 for SQL 2008 can now be downloaded

Hope this helps

Dave

 

Posted by davele | 2 Comments
Filed under: , ,

Tip: Make your Identity Keys go Further

It is extremely common to use computer generated Primary Keys in a table. eg:

OrderID INT PRIMARY KEY CLUSTERED IDENTITY(1,1) NOT NULL

Most people set the seed to 1. I don’t know why. Perhaps because it is the default value, maybe they display their keys to end-users, possibly they’ve never really thought about it.

But be aware that a seed = 1 halves the range of possible values.

Recommendation

The Seed can be a negative value, so set it to the most negative value you can. eg:  If you define your table with “OrderID SMALLINT IDENTITY(-32,768,1) then you have doubled the possible number of rows the table can contain before needing to increase the width of the key to an INT.

Consider using OrderID INT IDENTITY(-2,147,483,648,1or BIGINT IDENTITY(-9,223,372,036,854,775,808,1) or even TINYINT IDENTITY(0,1)

Enjoy,

   Dave

As always please post comments let me know if this is useful to you.

Thought for the day: (best read with a Forest Gump accent)

I have two twin sons. As the first one came out, he looked like a Pete, so I called him Pete. When the second one came out he looked exactly the same as his brother. So I called him re-Pete.

 

Posted by davele | 4 Comments
Filed under: ,

Database Design – Many to Many Join Tables

I was asked why my previous post suggested to “not use an Identity Column as a Key for Many to Many Join Tables”. This post outlines some of the pitfalls I’ve seen.

UPDATED: 17 May 09: To clarify a question about how to do this with higher normal forms <see Blue section at end>. I thought it may be worth sharing.

 

What are we talking about?

Using a Normalised design approach to your database schema, you will find that Many to Many Relationships between 2 objects are commonly expressed as another table, the Join Table. eg: Consider a Web site which allows you to customise your experience by setting your preference. eg: Smoking/Non-Smoking, Aisle/Window Seat, Rock/Classical/Jazz/Rap, Gay/Straight/Both/Neither. You may create the following tables.

Table 1: Customers (usual Login & demographic fields)

Table 2: Preferences (Pref_ID & Pref_Label)

Join Table: CustomerPreference (CustomerKey, PreferenceKey, & maybe other details about the relationship)

So the question is how could the Join Table be defined & what are the trade-off’s?

Design Alternative 1: Use the Primary Keys of the MANY tables as a Composite Key.

Sample code: Create the Primary Key as a composite key containing the 2 keys of the MANY tables & maybe other info about the relationship this row describes.

-- Define Table with the PRIMARY KEY as the Keys of the two MANY tables
CREATE TABLE [dbo].[CustPref](
    [CustID] [int] NOT NULL,
    [PrefID] [int] NOT NULL,
    [Details] [varchar](50) NULL,
 CONSTRAINT [PK_CustPref] PRIMARY KEY CLUSTERED ([CustID],[PrefID])
) 
GO

-- Define Foreign Keys to the two "MANY" tables.
ALTER TABLE [dbo].[CustPref]  WITH CHECK ADD CONSTRAINT [FK_CustPref_Customer] FOREIGN KEY([CustID])
REFERENCES [dbo].[Customer] ([CustID])
GO

ALTER TABLE [dbo].[CustPref] CHECK CONSTRAINT [FK_CustPref_Customer]
GO

ALTER TABLE [dbo].[CustPref]  WITH CHECK ADD CONSTRAINT [FK_CustPref_Preference] FOREIGN KEY([PrefID])
REFERENCES [dbo].[Preference] ([PrefID])
GO

ALTER TABLE [dbo].[CustPref] CHECK CONSTRAINT [FK_CustPref_Preference]
GO

Design Alternative 2: Give it its own Primary Key. (most likely machine generated)

Sample code: Create Key for the Join Table perhaps Identity Field, the 2 Primary Key of the MANY tables & maybe other info about the relationship this row describes. Optionally put a Unique Constraint on the two MANY keys.

-- Define Table with its own PRIMARY KEY.
CREATE TABLE [dbo].[CustPrefWithID](
    [CustPrefID] [int] PRIMARY KEY CLUSTERED IDENTITY(1,1) NOT NULL,
    [CustID] [int] NOT NULL,
    [PrefID] [int] NOT NULL,
    [Details] [varchar](50) NULL,
 CONSTRAINT [IX_CustPrefWithID] UNIQUE NONCLUSTERED ([CustID],[PrefID])
)
GO

-- Define Foreign Keys to the two "MANY" tables.
ALTER TABLE [dbo].[CustPrefWithID]  WITH CHECK ADD  CONSTRAINT [FK_CustPrefWithID_Customer] FOREIGN KEY([CustID])
REFERENCES [dbo].[Customer] ([CustID])
GO

ALTER TABLE [dbo].[CustPrefWithID] CHECK CONSTRAINT [FK_CustPrefWithID_Customer]
GO

ALTER TABLE [dbo].[CustPrefWithID]  WITH CHECK ADD  CONSTRAINT [FK_CustPrefWithID_Preference] FOREIGN KEY([PrefID])
REFERENCES [dbo].[Preference] ([PrefID])
GO

ALTER TABLE [dbo].[CustPrefWithID] CHECK CONSTRAINT [FK_CustPrefWithID_Preference]
GO

 

The challenges I see with Option 2 are:-

  1. You need an extra INT column. 
    Worst case you’ve just increased the row length by 50%. Which increases the number of pages in the table by ~50%. This increases the table scan reads by ~50% etc. Clearly if you needed other columns to describe this M:M relationship the % increase would be less significant. Join tables are often heavily read, so maximising the number of rows in each page can reduce IO.
  2. If you use the GUI designers, it will make the index on the PK, clustered. It is highly likely that you will get better perf if you cluster on one of the Foreign Keys, in this example the CustID.
  3. You need an extra Index, to hold the Unique Constraint. That causes extra maintenance, disk storage & Operations staff may need to defrag it.
  4. Worst still. I commonly see databases where they’ve forgotten to add the Unique Constraint. Because of this they never notice the error when they add the same combination multiple times. This usually means they don’t delete old or redundant relationships. I once saw a 2GB Table that only contained ~400K of Unique rows, the rest were duplicates & other garbage they didn’t need (LastUpdatedBy = “AnonymousWebUser”). This extra baggage had a massive adverse Perf impact.

The arguments for this approach are:-

  • Everything can be joined with everything else & so eventually you have these really long composite keys.

For Example: An Education system has Tables for Course, Location, Teacher, Student.
A Class             is a M:M join of a Course, Location, Teacher & Time. ie: Many Year 10 Maths Classes at same School in 2nd Period.
An Enrolment   is a M:M join of Student & Class.
An Assignment if a few students collaborate on a project it could be a M:M join of a few enrolments & a time. (need to ensure that only students enrolled in the course can submit work)

Clearly the composite key approach can become unwieldy, so at some point you might find it worthwhile creating a Unique Key for a M:M table. But don’t overlook the advantage to carrying all these FK’s around in your design. It gives the optimiser many more alternatives & can save a huge number joins. ie: If I want to create a report listing all the assignments grouped by Teacher, I could just join the Teacher & Assignments table, saving the 4 Table Join; Teacher, Class, Enrolment, Assignment.

 

Last thoughts

I realise that design is personal & not everyone agrees with my opinions above. I’d love to hear your experience; either for, against or different to the points raised in this post

Hope this helps

Dave

= = = = = = = = < UPDATE 17 May 09 > = = = = = = = =

The QUESTION: Many to Many conundrum – Using DRI to enforce complex constraints / business relationships

Consider this:

Table A has 2 child tables ( B & C )
The PK of B and C is an identity, and they both have a FK back to Table A.

I have a table D, which is a join table on B and C
Table D has PK of an identity and FK's back to B and C.

Here's some example Data

Table A:  Two rows .... Org1 and Org2
Table B:  Two rows .... 1 linked to Org 1 and 1 linked to Org 2  ( PK ids are 44(Org1) and 45(Org2) )
Table C:  Two rows .... 1 linked to Org 1 and 1 linked to Org 2  ( PK ids are 106(Org1) and 107(Org2) )

I can add a row to Table D which has an 'B' id of "44" and a 'C' id of "107"
This is invalid ... the B id in Table D refers back to Org1 and the C id in Table D refers back to Org2
If I use composite primary keys I can stop this happening, but I cannot see how to stop this if I use identities ...

Alan
- - - -
I’m not clear on what you are saying.  I think that you agreeing with me, in that creating an Identity col in Table D is a bad idea, Correct?
(Actually is not a bad idea, but by itself, it is adding overhead & leaving you exposed to data corruption issues.)

Below is a diagram of what I think you described. And a way to use Declarative Referential Integrity (DRI) constraints to enforce the correct relationship with Table A. These sorts of problems are why 4th & 5th Normal Form were introduced.

clip_image002

Dave
- - - -

Thank you very much for your reply, that's cleared up loads for me.
Obviously, you could still have an identity on table D, and then enforce a unique constraint on the the other 3 fields, but you wouldn't be gaining much by this.

Alan
- - - -

True there is no one correct way (there are plenty of incorrect ways or those that will yield potential for bad data)

  1. If your data model has some kind of sub-domain ie: Product Design vs Sales OR (Courses & Classes) vs (Students & Enrolments). Then sometimes having an Identity key on TableD, means you don’t have to carry the 3 cols with all their constraints through all the other tables in your data model.
    Eg: In an educational institution: TableA = Classes, TableB = Teachers who teach that Class, TableC = Venues suitable for that class (think Science Labs vs PE/Sport). TableD could be a Class. (An instance of that course/teacher/venue & date). Giving TableD an uniqueID (ie: Class ID), makes it simpler with the next set of tables (Students, Class Enrolments, Assignments, Payments, Exam Results etc) to have just the one FK to TableD.
    Clearly you’d have to weigh up the benefits (eg: Less overhead in FK lookups to enforce the DRI, narrower rows) vs disadvantage (eg: need join thru TableD if you want to Group or filter on TableA,B or C)
  2. I’m unclear if you will achieve much with a unique key over the 3 cols unless you also have the 2 FK constraints. But that really depends on your use of data. Good idea if you’ve designed it well with strong normalisation. But if you had other FK’s (ie a  Time column) it may be OK to have duplicates, as the uniqueness is in the extra columns.  Eg: This car drove over this bridge & the time, is sufficient to do billing. But I agree I’d prefer the unique constraint on all 4 cols.

Thanks for the feedback
Dave

Posted by davele | 4 Comments

SQL Server NOLOCK Hint & other poor ideas.

Frequently I see production code, created by professional development teams, peppered with NOLOCK & other TSQL Hints.

While totally understandable, as it is a common recommendation by many internet posts & often found in their sample code, this is a really bad practice.
It often results in very obscure, hard to reproduce bugs and can cause data to get corrupted.

 

Thought 1: TSQL HINTs in General

As a general rule TSQL HINTs should only be used as a last resort. Both those responsible for the ANSI SQL standard & the Microsoft SQL Development Team have given a lot of thought about what is the safest, most desirable default values for transactions & query execution. It would seem logical that your default Coding Standard should be to follow those defaults and not some code snippet you found on the internet.

Recommendation 1: Do not use any HINTs until your testing proves that you have an issue that can’t be solved any other way than by using a HINT. 

  • Be aware that any testing you do will be unique to that Specific Edition, Specific Version & Service Pack. The optimiser is constantly being enhanced, in a future release it might change to better handle whatever it is that you are hinting.
  • On more than one occasion I’ve had customers request a switch to turn off the Optimiser HINTs generated by some s/w package they’ve purchased. They’ve discovered that the ISV’s queries actually run much faster without the hints, perhaps the hints were useful 10 years ago is say, SQL 6.5, but are now a hindrance in a later release of SQL.
  • Often you can rewrite your query &/or modify schema to get a much better result.

Recommendation 2: If you use a HINT, prove it via testing & document it.

If you use a HINT, document why. I’d expect at least :-

  1. The issue or performance problem you encountered, How it worked without HINTs & how it worked with the Hint.
  2. The Version, Edition, Patch Level you tested it on. (Enterprise Edition runs many more operations in parallel than Standard, this can make a difference)
  3. Also nice if your app provides a configuration option to remove it your hints OR maybe give the customer the ability to edit your stored proc to remove it.

More than once I’ve looked at a Schema or TSQL Query & thought “Either this designer was brilliant & had such foresight to anticipate some obscure issue I’ve not even considered OR they have no clue about databases”. Unfortunately it is almost impossible to know with total certainty. So please tell the poor mongrels who maintain your code, what you were thinking. Preferably put the comments into the TSQL Code, as nearly any other place the documentation will become separated from the code.

 

Thought 2: TSQL NOLOCK / READ UNCOMMITTED HINT

This Hint is much more dangerous than its name suggests. And that it why most people who don’t understand the problem, recommend it. It creates “incredibly hard to reproduce” bugs. The type that often destroy your end-users confidence in your product & your company.

But it does make nasty warnings/errors go away without the need to really fix the problem. Similar to short sighted “tips” from other disciplines are :-

  1. Turning off the Compiler Warnings about Implicit Type conversion can speed development. NB: Comparing an INT to a SHORT is classic cause of an infinite loop.
  2. Turning up your car stereo can drown out the grinding noise of an engine with no oil.
  3. Turning up the volume of your MP3 player can save you from the terror & desperate leap to safety when you walk onto the road with your back to the oncoming traffic.
  4. Folding your arms on the “seatback in front of you” will make a big difference when you fly into the ground upside down at 900 kph. OK there may be some merit to this one, stops you annoying the person next to you.

What many people think NOLOCK is doing

Most people think the NOLOCK hint just reads rows & doesn’t have to wait till others have committed their updates or selects. If someone is updating, that is OK. If they’ve changed a value then 99.999% of the time they will commit, so it’s OK to read it before they commit. If they haven’t changed the record yet then it saves me waiting, its like my transaction happened before theirs did.

The Problem

The issue is that transactions do more than just update the row. Often they require an index to be updated OR they run out of space on the data page. This may require new pages to be allocated & existing rows on that page to be moved, called a PageSplit. It is possible for your select to completely miss a number of rows &/or count other rows twice. This has been well documented by a number of highly reputable sources, including the SQL Server Development team. So I wont repeat it here. For the details visit the links below.

SQL CAT: Previously committed rows might be missed if NOLOCK hint is used

Tony Rogerson's post, Timebomb - The Consistency problem with NOLOCK / READ UNCOMMITTED

Itzik Ben-Gan's SQL Server Mag Article on Allocation Order scans

NOLOCK Optimizer Hint May Cause Transient Corruption Errors in the SQL Server Error Log

Excuses

  • We always do that / It was just in the sample code I read. => Now you know better.
  • But I keep getting these Deadlock messages. => Solve the problem (see below)  don’t just ignore the warnings.
  • I only use it on small tables which heaps of people read & it rarely changes. => Shared Locks don’t block other shared locks. Maybe you could have your Updates change 1 row per transaction.

The solution

Unfortunately there is no 1 line recommendation I can give you that will make your Deadlock &/or other perf issues go away. People have written entire books on the subject. But a few things to consider are:-

  • Use Stored Procedures for everything. They provide a level of encapsulation or code isolation that will allow someone to change your schema & fix perf issues without needing to understand your code. Note: Creating 3 stored procs for every table; p_Insert, p_Update & p_Delete is OK but not really what I’m talking about. I prefer procs that do a unit of work that may involve multiple tables, eg: p_CreateNewCustomer() or p_NewOrder()
  • Improve your schema
    Keep your rows short – avoid adding additional audit columns (ie: LastUpdatedBy) if there is no business plan to read them.
    Ensure your Many to Many tables use both foreign keys as a the unique composite key (Primary key), ie: an Identity Column as a Primary Key is not appropriate for these tables.
  • Keep your transactions short
    Avoid having a huge Selects sandwiched between two updates in the same transaction. (this is like Loop optimisation by taking the invariant statements out of the loop).
    Avoid SELECTing a row & then changing it, eg: Instead of SELECT VALUE, UPDATE VALUE = OLD VALUE+1. Just Update the “Original value +1” as a single statement.
  • Avoid using cursors.
    Cursors are not bad but often you can find a much more efficient way to complete a task. The optimiser is forced to do “Row by Row” changes which prevents most forms of optimisation, parallelism & multi-buffered operations.
  • Try to acquire locks in the same sequence for all your transactions. eg: have all your stored procedures Lock the InvoiceHeader before the InvoiceDetails. Don’t write half one way & the other half the opposite.
  • Use Snapshot Isolation.
    But test it, your TEMPDB config might need attention.
  • Think about using a READPAST hint. If a row or page is locked you just don’t read it. Often that is OK as those “Rows” were being used anyway. eg: in any ticketing system; Airline seats, Theatre, Hotel, where you have many customers competing for finite resources, you often know the total resources anyway. In one system we drew all the seats in a concert hall & coloured them orange. Then Selected all the seats on that night with a READPAST hint. Those that were RESERVED or AVAILABLE were returned. We coloured them appropriately. Any seat not returned was possibly being locked by another reservations clerk, so remained in Orange. If they hit refresh again, these seats typically turned Red (booked)
  • SQL Broker
    Use SQL Service Broker to break your transactions up into an async component. These smaller transactions might not block for as long OR you may be able to block the queue in heavy load periods & have that part of the transaction processed in the evening.

Update to this Post

1. If NOLOCK is so bad why have it at all?

    Because sometimes accuracy is not so important. If you are plotting something on a line chart & the line is out by 1-2% you possibly wouldn’t notice, what most people would look at is the trend. Similarly, if you are putting a number on a screen & refreshing it periodically (ie: %CPU or “Orders received in the past 10 mins”, most people will only look at the 1st 2-3 significant digits. eg: If a traffic counter measured 154,218 cars went thru an intersection between 6-7am & 572,621 from 8-9am. Your brain possibly rounds it to ~150K & ~575K respectively. Unless you are charging a toll for each car, the thing most interesting is “how does that compare to other time periods”

2. How does it cause data corruption?

   Mostly when you use the SELECT .. WITH NOLOCK as the basis of some other Update or Insert. Some rows will miss out on whatever changes you thought should be applied to them.

 

I hope this assists you to improve you design Or at least avoid creating issues that will be impossible to debug in production.

All feedback & comments welcome.

Dave.

 

Thought for the day, (which sums up my feelings about Cursors & Hints): There is no Right or Wrong, only outcome.

Posted by davele | 5 Comments
Filed under: ,

Boost your Bottomline – BI Breakfast with New Horizons

Recently I’ve been flying around Australia delivering a 90 min seminar called Boost your BottomLine with SQL Server BI. This post is purely to make the Slides available for the audience.


The audience was predominantly technical managers & architects in companies who owned SQL Server.
The goal was to expose them to SQL features other than the database.
The desire was by exposing them to the BI capability in the product we might stimulate their thinking.
The hope was they might think of new ways to improve the efficiency & effectiveness of their company.
The dream was by better using what they already have, more people will remain employed & the recession will not be as bad.

Without the demos or sound, I suspect this deck will only be useful for those who attended the seminar. Still it is here for you if you want it.

This deck is “a mile wide & an inch deep”. If you have solid experience in SQL 2008 BI components. This is not for you. But if you want a quick overview, maybe you might find something here

(Download the PPT deck from this seminar here)

NB: This is in Powerpoint 2007 format (much smaller). If you are using an earlier version of Office you will need to download the Microsoft Office Compatibility Pack for Word, Excel, and PowerPoint 2007 File Formats

Enjoy

Dave

Quote: The quality of the answer is determined by the quality of the question.

ie: It you’re not getting the answers / solutions you need. Start thinking about it from a different perspective.

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.

 image161[1]_thumbimage13_thumb    image131_thumb[1][1]

 

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

image

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.
    image

Step 6: Set the Color Property to: =iif( Fields!myField.Value < 0, “Red”, “Black”)

image

The Result: This should display as.

image

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 Property

Tip 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.

             image71_thumb

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.

             image4_thumb

Step 1b. Select the Code Tab & enter or paste your code.

              image1011_thumb

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 Function

 Step 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.

image16_thumb

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.

image191[1]_thumb

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.

Posted by davele | 8 Comments

SQL Reporting "How to" - Conditional Color 2/4: Functions for Tables & Charts

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.)

 

SQL Reporting "How to" – Conditional Color for Tables & Charts. 2/4

 

Part 2/4 Continuous Color functions - Hue

In Part 1, I covered simple ways to select from a fixed set of colors & how to assign them to the Color & Backcolor Properties of a Report Item (ie: report textbox), Plus a few other tips.

In Part 2, I cover the algorithm logic & provide many samples you might choose to use as is, or as a basis to enhance. This should give you sufficient info to get them working in most report items, ie Tables, Textboxes etc.

In Part 3, I cover the algorithm logic & provide many samples you might choose to use as is, or as a basis to enhance. This should give you sufficient info to get them working in most report items, ie Tables, Textboxes etc.

In Part 4, I expand on Part 2 by looking at special needs of charting & multidimensional grouping.

Example of using some of the techniques outlined in Part 2 to draw attention to specific values in a table.

image13_thumb

Contents - Part 2: Continuous Color functions - Hue

A quick “Computer Colors” 101

The algorithm logic

 Changing the color (hue)
           ColorRYG: Red – Yellow – Green

     Optimising the code – Using Module Level Variables

     Swapping the Color Transition
           ColorRPB: Red – Purple – Blue
           ColorBPR: Blue – Purple - Red

     The Rainbow Functions
           Rainbow3: Cyan – Green – Yellow – Red
           Rainbow4: Blue – Cyan – Green – Yellow – Red
           Rainbow5: Purple – Blue – Cyan – Green – Yellow – Red
           Rainbow6: Red – Purple – Blue – Cyan – Green – Yellow – Red

     Using the parameters to achieve different effects / emphasis.

 

Overview

When displaying continuous color you have two dimensions you can vary; (i) the brightness (eg: Light blue to Dark Blue) & (ii) the Hue (the color).

Changing the brightness, also called Saturation,  is nice because every color can fade to white (or black) & then fade back out to any other color. So this permits you to easily combine any color with any other. eg: Gender: Blue for Boys & Pink for girls, or Rainfall: Brown for Deserts thru to Olive for Forests.

Changing the Color (Hue) is nice because you can maintain the same light intensity, it seems to look nicer, & can more thru multiple “neutral” zones not just the one White/black. The disadvantage is that colors only combine thru the order of the frequency spectrum, as seen in a rainbow or color wheel.

 

A quick “Computer Colors” 101

Colors on most computers are represented by 24 bits, this consists of three 8 bit Octets representing in order Red, Green, Blue abbreviated to RGB. .NET provides a variety of methods / functions to help to convert this into human readable form. Often it is simply displayed in hex (eg: #FF00FF which translates to Max Red, Min Green, Max Blue which displays as Purple.)

Sometimes you will see ARGB, referring to a 32 bit color which is a simple extension adding an alpha channel which displays how transparent the color will be. While .NET Colors classes uses ARGB & SQL2008 color dialogs let you specify ARGB color. The Reporting Services codes you generate only need to be RGB.

As a handy reference I’ve included this table showing the transition around the outermost edge of a color wheel; Bright Red, thru Green, Blue & back to Red. This is also an example of how you can easily incorporate this color into your tables & chart.

image

Changing the Color (Hue) is quite straightforward. The colors are represented by RGB (Red,Green,Blue) each color group is 1 byte, so it ranges from 0 – 255 (or 0x00 - 0xFF).

If you are writing your own function to change color it is easy to confuse what color octet you need to be changing. I hope the table above will assist in helping you see which RGB group you need to adjust in order to move thru the rainbow.

It is worth noting that I’ve gone with the maximum intensity, leaving the non-changing values at their extremes (ie 00 or FF). If you’d prefer pastels or less bright, you can reduce the range of values (eg: perhaps 04 – C0), in order to get that effect.

I hope you might find it a handy reference when writing code. Most of routines remain the same, you just adjust the order of the color creation statements. Looking at what column you are changing eg: Red to Yellow may help you realise that it is the middle octet you need to be changing.

Disclaimer: This is only intended to give you a background on what you need to use color in a .NET environment. Other computer platforms & graphics systems may offer a completely different way to encode color.  

 

The algorithm logic.

Regardless of moving thru Colors & Shades, the logic for all the routines included in this set of articles are similar.

  1. As seen above, in a 32 or 24 bit color system there is only a finite number of steps to move from one base colour (eg: Red ) to another (eg Yellow ). To move from Red (#FF0000) to Yellow (#FFFF00), you change the Green byte. There is only 256 unique color steps.
  2. We need to discover the range of data values you wish to put the colors to. eg: If the highest value in your data is 50 & the lowest value is -50. Then your range is 100.
  3. Then determine the size of data change in order to make one color step.
    ie: Data Range / Color steps = 100/256 = 0.39. So if your data has 2 values 1 & 1.8 there will be 2 color steps different. As 0.8 / 0.39 = 2 ignoring remainder.
  4. Find the appropriate color by, <Distance from Lowest value> * Color steps.

Example: Your range is 100 & the minimum of –50 is Red. If a DataPoint has a value = 10, it will be 60 color steps above Red. Looking at the Green byte, for Red the Hex is 0x00. So 60/0.36 = 154 or 0x99. So the color for the value of "10" is 0xFF9900.

 

 1. Changing the color (hue)

While it is simpler to write a function to just transition from one color to another purely by changing only one of the octets (R, G or B). It is not as useful a moving thru 2 scales.  Say, Red to Yellow & then Yellow to Green. Red to Green seems to be the most popular & ironically the one most likely to trouble those affected by colour blindness.

To make this work we need know 4 values; the Max, the Min, the value which you want the middle color to be & the value of the data you need the color for.

Because we want the gradient to be the same from either direction from the middle, we determine which has the largest range, (Max – Middle) or (Middle – Min). Using the greatest range we then determine the step size & follow the algorithm outlined above. Except as we now have 2 color ranges we need to determine which range that our data point belongs to by comparing it to the neutral value.

As mentioned below you might want to make the code more robust by validating the parameter values. See “Warning” below.

It is also possible to optimise the code by only doing the range test once.  But be careful as it may constrain you to only using it in one part of the report.   See “Optimising the code” section below.

 

ColorRYG: Red – Yellow – Green

Not only is the code below intended to be an example of implementing the algorithm logic. This function is the one I use the most. People love stoplight colors. People don’t seem concerned about color blind viewer, “they can read the numbers or shapes” 

Sample Uses: Everything, especially where you can equate good & bad.  eg: Financial Progress: Above/Below Budgets. Production Inefficiencies, HR Employee churn, Road injury, Delivery delays,  Days Sales Outstanding (DSO) etc.

image image13_thumb[9]

Note in all the sample graphics I’m using just 0 – 255, this is to help you see what the function displays. The functions aren’t limited to that range, in fact it is designed to work with any numbers [positive or negative) & any size interval.

Public Function ColorRYG(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal, ByVal Neutral As Decimal) As String
    'Example: =code.ColorBack(expression, Max(expression), Min(expression), 0)
    '=code.colorback( Fields!Sales.Value,max( Fields!Sales.Value),min( Fields!Sales.Value),0)
    'Find Largest Range
    Dim decRange As Decimal
    Dim decPosRange As Decimal = Math.Abs(MaxPositive - Neutral)
    Dim decNegRange As Decimal = Math.Abs(MaxNegative - Neutral)

    decRange = IIf(decPosRange > decNegRange, decPosRange, decNegRange)

    'Force color into Max-Min Range. Important if you want to Clip the color display to a subset of the data range. 
Value = Switch((Value > MaxPositive), MaxPositive, Value < MaxNegative, MaxNegative, True, Value)
    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(Math.Round((Value - Neutral) * decColorInc))

    'Return Appropriate +ve or -ve color
    Dim strColor As String
    If iColor >= 0 Then
        'Green
        iColor = 255 - iColor 'Thus 0 = White & 255 = Green
        strColor = "#" & iColor.ToString("X2") & "FF00"
    Else
        'Red
        iColor = iColor + 255  'NB iColour is -ve;  -1 - -255 
        strColor = "#FF" & Math.Abs(iColor).ToString("X2") & "00"
    End If
    Return strColor
End Function

Warning: To reduce computing overhead I’ve not included many parameter checks in all the code samples in this post. That might also be OK for you especially if you are passing values obtained from the data. ie: MAX(myfield), Min(Myfield) & Avg(MyField).    

If you expect to have data values beyond the Max/Min values you provide, I suggest you include additional error checking similar to :-

  1. Is Neutral between MaxPositive & MinNegative?
  2. If Value is greater than MaxPositive, set to MaxPositive
  3. If Value is Less than MaxNegative, set to MaxNegative
    'Force color into Max-Min Range. Important if you want to Clip the color display to a subset of the data range.
    Value = Switch((Value > MaxPositive), MaxPositive, Value < MaxNegative, MaxNegative, True, Value)
    
    'Find appropriate color shade
    Dim iColor As Integer = CInt(Math.Round((Value - Neutral) * decColorInc))
  4. If MaxPositive < MaxNegative, swap their values. (or let it die & have the report developer catch their error. )

What you do in these circumstances is up to you. Some people may just hard code an “Error” color to return, perhaps Black or Red, Others may just return “transparent”

 

Optimising the code – Using Module Level Variables.

It is possible to store state in module level variables. So rather than calculate the Range & Color increment for each data value in the report, you could do it once on the first call & just refer to it for the subsequent calls.

On an extremely large report, or one used very frequently, this may save some CPU cycles.

The disadvantage is that the optimisation of the color coding is only going to be called once. Subsequent calls assume the same set of parameters. This may be OK if you are only using in one column or chart  or if all report items need the same Min,max & threshold values (perhaps KPI’s all set the same).  But it would prevent you from having different color ranges per group. (unless you create multiple copies of your  function each with slightly different name.)

The main reason I mention it here is to provide an example of using Module level variables, as it might handy for other functions you write. If Report Services didn’t already provide functions like; Previous, RowNumber, RunningValue, it would be easy to write your own equivalents using this technique.  

So think broader. You could write your own Moving Average function or some other calculation that uses info from prior rows. If your datasource is transactional or XML it is much more efficient to code-up your own function in Reporting services.  Note: If your datasouce is Analysis Services, do it in your MDX.

Tip: For more on writing your own Moving Average Function, see Get More Out of SQL Server Reporting Services Charts its in the last 1/3rd of the article. This whole article is worth a read.

' Module level Variables 
Private bInitialized As Boolean = False
Private decColorInc As Decimal

Public Function ColorBack(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal, ByVal Neutral As Decimal) As String
    'Example: =code.ColorBack(expression, Max(expression), Min(expression), 0)
    '=code.colorback( Fields!Sales.Value,max( Fields!Sales.Value),min( Fields!Sales.Value),0)

    '--- Execute once per report -----
    If Not bInitialized Then
        '-- Find Largest Range
        Dim decPosRange As Decimal = Math.Abs(MaxPositive - Neutral)
        Dim decNegRange As Decimal = Math.Abs(MaxNegative - Neutral)
        Dim decRange As Decimal = IIf(decPosRange > decNegRange, decPosRange, decNegRange)

        '-- Find Delta required to change color by 1/255th of a shade
        decColorInc = 255 / decRange

        bInitialized = True
    End If

    '-- Find appropriate color shade
    Dim iColor As Integer = CInt(Math.Round((Value - Neutral) * decColorInc))

    '-- Return Appropriate +ve or -ve color
    Dim strColor As String
    If iColor >= 0 Then
        iColor = 255 - iColor 'Thus 0 = White & 255 = Green
        strColor = "#" & iColor.ToString("X2") & "FF" & iColor.ToString("X2")  'xxFFxx 
    Else
        iColor = iColor + 255  'NB iColour is -ve;  -1 - -255 
        strColor = "#FF" & Math.Abs(iColor).ToString("X2") & Math.Abs(iColor).ToString("X2") 'FFxxxx 
    End If
    Return strColor
End Function

 

Swapping the Color Transition

This section covers how you specify which value you want to represent the lowest values & which the higher ones.

To explore this concept I created 2 functions ColorBPR (Blue/Purple/Red) & ColorRPB. As you will notice both of these functions are almost identical to the ColorRYG function. The only difference is which RYG element we change & what color we start with. So to get the mirror order we just swap the 2 lines that create the color.

image41_thumb[1]

ColorRPB (Red/Purple/Blue) is the 1st column in the table above.

Public Function ColorRPB(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal, ByVal Neutral As Decimal) As String
    'Example: =code.ColorRPB(expression, Max(expression), Min(expression), 0)
    '=code.ColorRPB( Fields!Sales.Value,max( Fields!Sales.Value),min( Fields!Sales.Value),0)
    'Find Largest Range
    Dim decRange As Decimal
    Dim decPosRange As Decimal = Math.Abs(MaxPositive - Neutral)
    Dim decNegRange As Decimal = Math.Abs(MaxNegative - Neutral)

    decRange = CInt(IIf(decPosRange > decNegRange, decPosRange, decNegRange))

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(Math.Round((Value - Neutral) * decColorInc))

    'Return Appropriate +ve or -ve color
    Dim strColor As String
    If iColor >= 0 Then
        'Blue
        iColor = 255 - iColor 'Thus 0 = Blue & 255 = Purple
        strColor = "#" & iColor.ToString("X2") & "00FF"         '<<=== Swap these Lines
    Else
        'Red
        iColor = iColor + 255  'NB iColour is -ve;  -1 - -255 
        strColor = "#FF00" & Math.Abs(iColor).ToString("X2")    '<<=== Swap these Lines
    End If
    Return strColor
End Function

 

ColorBPR (Blue/Purple/Red) is the 2nd column table shown in the graphic above.

Public Function ColorBPR(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal, ByVal Neutral As Decimal) As String
    'Example: =code.ColorBPR(expression, Max(expression), Min(expression), 0)
    '=code.ColorBPR( Fields!Sales.Value,max( Fields!Sales.Value),min( Fields!Sales.Value),0)
    'Find Largest Range
    Dim decRange As Decimal
    Dim decPosRange As Decimal = Math.Abs(MaxPositive - Neutral)
    Dim decNegRange As Decimal = Math.Abs(MaxNegative - Neutral)

    decRange = CInt(IIf(decPosRange > decNegRange, decPosRange, decNegRange))

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(Math.Round((Value - Neutral) * decColorInc))

    'Return Appropriate +ve or -ve color
    Dim strColor As String
    If iColor >= 0 Then
        'Red
        iColor = 255 - iColor 'Thus 0 = Red & 255 = Purple
        strColor = "#FF00" & Math.Abs(iColor).ToString("X2")        '<<=== Swap these Lines
    Else
        'Blue
        iColor = iColor + 255  'Thus 0 = Purple & 255 = Blue
        strColor = "#" & Math.Abs(iColor).ToString("X2") & "00FF"   '<<=== Swap these Lines
    End If
    Return strColor
End Function

 

The Rainbow Functions

The Rainbow functions are here just to assist those who don’t want to think about the color chart & which RGB byte to change in order to move from one value to the other. These functions are limited in that they only take the 2 two extremes (Max & Min) & then generate a smooth transition of color between them.
You can make them more useful by extending them with additional parameters that permit you specify a specific value for each transition point.

To do so, look to the logic provided in ColorRYG & extend it to create a range for each color transition. eg:

Dim decPosRange As Decimal = Math.Abs(MaxPositive - Neutral)
Dim decNegRange As Decimal = Math.Abs(MaxNegative - Neutral)

decRange = IIf(decPosRange > decNegRange, decPosRange, decNegRange)

I’ve not provided this solution “out-of-the-box” due to the variety of permutations you could desire. The two key ones being finding the set of parameters with the largest range & letting that determine how fast colors change, or just changing colors evenly (but at different rates) between the values you supply as middle threshold parameters.

NB: In case you wonder, the numeral X after the RainbowX function name indicates the number of transitions, not number of colors. 

image11_thumb image

NB: Some people feel that the Rainbow of colors is a bit bright. If you like, try washing them out either by making them more transparent (in SQL2008, Alpha value) or combine with the Saturation code <below> & add “whiteness” (by not going all the way to #00, in the non-transitioning byte – the one that is changing the color.)

Rainbow3: Cyan – Green – Yellow – Red

Sample Uses: Showing Human habitable temperatures. ie: Cyan = 0 °C, Green = 24 °C, Yellow = 37 °C & Red=60 °C (feel free to convert to your scale of choice; Fahrenheit or Kelvin).

Achievement: Red = Poor, Yellow = Borderline, Green = on target, Blue = Blew the numbers off the chart!!

Public Function ColorRainbow3(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal) As String
    'Find Largest Range
    Dim decRange As Decimal = MaxPositive - MaxNegative
    Dim decColorRange As Decimal = decRange / 3

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decColorRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(((Value - MaxNegative) Mod decColorRange) * decColorInc)

    'Return Appropriate  color
    Dim strColor As String

    Select Case Value
        Case Is >= MaxPositive    'Red (100)
            strColor = "#FF0000"
        Case Is >= MaxNegative + 2 * decColorRange  ' Yellow (80) -> Red
            iColor = 255 - iColor
            strColor = "#FF" & iColor.ToString("X2") & "00"
        Case Is >= MaxNegative + decColorRange  ' Green (60) -> Yellow
            'iColor = 255 - iColor 
            strColor = "#" & iColor.ToString("X2") & "FF00"
        Case Is >= MaxNegative    ' Cyan (40) -> Green
            iColor = 255 - iColor
            strColor = "#00FF" & iColor.ToString("X2")
        Case Is < MaxNegative               ' Blue
            strColor = "#00FF00"
        Case Else
            strColor = "Transparent"
    End Select
    Return strColor
End Function

 

Rainbow4: Blue – Cyan – Green – Yellow – Red

Sample Uses:
Once more, Human habitable temperatures, but extended to include colder climates like USA in winter.

Rainfall, Fire Risk, Crime Rates, Insurance Risk, &/or anything where 2 factors mix.

Public Function ColorRainbow4(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal) As String
    'Find Largest Range
    Dim decRange As Decimal = MaxPositive - MaxNegative
    Dim decColorRange As Decimal = decRange / 4

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decColorRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(((Value - MaxNegative) Mod decColorRange) * decColorInc)

    'Return Appropriate  color
    Dim strColor As String

    Select Case Value
        Case Is >= MaxPositive    'Red (100)
            strColor = "#FF0000"
        Case Is >= MaxNegative + 3 * decColorRange  ' Yellow (80) -> Red
            iColor = 255 - iColor
            strColor = "#FF" & iColor.ToString("X2") & "00"
        Case Is >= MaxNegative + 2 * decColorRange ' Green (60) -> Yellow
            'iColor = 255 - iColor 
            strColor = "#" & iColor.ToString("X2") & "FF00"
        Case Is >= MaxNegative + decColorRange   ' Cyan (40) -> Green
            iColor = 255 - iColor
            strColor = "#00FF" & iColor.ToString("X2")
        Case Is >= MaxNegative    ' Blue(20) -> Cyan
            'iColor = 255 - iColor 
            strColor = "#00" & iColor.ToString("X2") & "FF"
        Case Is < MaxNegative               ' Blue
            strColor = "#0000FF"
        Case Else
            strColor = "Transparent"
    End Select
    Return strColor
End Function

 

Rainbow5: Purple – Blue – Cyan – Green – Yellow – Red

Sample Uses:
Once more, Human habitable temperatures, I used this in the World Temps graphic above.
Public Function ColorRainbow5(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal) As String
    'Find Largest Range
    Dim decRange As Decimal = MaxPositive - MaxNegative
    Dim decColorRange As Decimal = decRange / 5

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decColorRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(((Value - MaxNegative) Mod decColorRange) * decColorInc)

    'Return Appropriate  color
    Dim strColor As String

    Select Case Value
        Case Is >= MaxPositive    'Red (100)
            strColor = "#FF0000"
        Case Is >= MaxNegative + 4 * decColorRange  ' Yellow (80) -> Red
            iColor = 255 - iColor
            strColor = "#FF" & iColor.ToString("X2") & "00"
        Case Is >= MaxNegative + 3 * decColorRange ' Green (60) -> Yellow
            'iColor = 255 - iColor 
            strColor = "#" & iColor.ToString("X2") & "FF00"
        Case Is >= MaxNegative + 2 * decColorRange  ' Cyan (40) -> Green
            iColor = 255 - iColor
            strColor = "#00FF" & iColor.ToString("X2")
        Case Is >= MaxNegative + decColorRange   ' Blue(20) -> Cyan
            'iColor = 255 - iColor 
            strColor = "#00" & iColor.ToString("X2") & "FF"
        Case Is >= MaxNegative      ' Purple(0) -> Blue
            iColor = 255 - iColor
            strColor = "#" & iColor.ToString("X2") & "00FF"
        Case Is < MaxNegative               ' Blue
            strColor = "#0000FF"
        Case Else
            strColor = "Transparent"
    End Select
    Return strColor
End Function

 

Rainbow6: Red – Purple – Blue – Cyan – Green – Yellow – Red

Sample Uses:
Showing relative combination of 2 independent factors. Say you are in insurance & need to display the possibility of Flood Risk & Bushfire Risk for a property:-

  • High Fire Risk = Red, High Flood Risk = Blue. Zero Flood & Zero Fire Risk = Green
  • Thus you move from Red to Green showing Fire Risk for properties with Negligible Flood risk.
  • You move from Blue to Green showing Flood Risk for properties with Negligible Fire risk.
  • The Red to Blue showing relative risk of Flood & Bush Fire

Once more, Human habitable temperatures, but extended to include colder climates like Antarctica, especially if you change the code from the first Red into white, so that it moves from White to Purple.

Public Function ColorRainbow6(ByVal Value As Decimal, ByVal MaxPositive As Decimal, ByVal MaxNegative As Decimal) As String
    'Find Largest Range
    Dim decRange As Decimal = MaxPositive - MaxNegative
    Dim decColorRange As Decimal = decRange / 6

    'Find Delta required to change color by 1/255th of a shade
    Dim decColorInc As Decimal = 255 / decColorRange

    'Find appropriate color shade
    Dim iColor As Integer = CInt(((Value - MaxNegative) Mod decColorRange) * decColorInc)

    'Return Appropriate  color
    Dim strColor As String

    Select Case Value
        Case Is >= MaxPositive    'Red (100)
            strColor = "#FF0000"
        Case Is >= MaxNegative + 5 * decColorRange  ' Yellow (80) -> Red
            iColor = 255 - iColor
            strColor = "#FF" & iColor.ToString("X2") & "00"
        Case Is >= MaxNegative + 4 * decColorRange ' Green (60) -> Yellow
            'iColor = 255 - iColor 
            strColor = "#" & iColor.ToString("X2") & "FF00"
        Case Is >= MaxNegative + 3 * decColorRange  ' Cyan (40) -> Green
            iColor = 255 - iColor
            strColor = "#00FF" & iColor.ToString("X2")
        Case Is >= MaxNegative + 2 * decColorRange  ' Blue(20) -> Cyan
            'iColor = 255 - iColor 
            strColor = "#00" & iColor.ToString("X2") & "FF"
        Case Is >= MaxNegative + decColorRange      ' Purple(0) -> Blue
            iColor = 255 - iColor
            strColor = "#" & iColor.ToString("X2") & "00FF"
        Case Is >= MaxNegative      ' Red -> Purple(0)
            'iColor = 255 - iColor 
            strColor = "#FF00" & iColor.ToString("X2")
        Case Is < MaxNegative               ' Blue
            strColor = "#FF0000" '"#0000FF"
        Case Else ' Will never get here
            strColor = "Transparent"
    End Select
    Return strColor
End Function

 

Using the parameters to achieve different effects / emphasis.

Visual Grouping & Sorting - Color by specifying the endpoint extremes. (Value, Max, Min)

When writing code to create a color gradient you need to decide if the middle position is important. In some cases, all you want to do is to visually group similar values with a similar color. For this it might be sufficient to specify a minimum & maximum value & have the colors slide evenly between the two. A common use example is; setting the highest number is Green, the lowest to Red & any gradients in between may assist you to quickly compare the data values. NB: Given the significant number of males who are color blind (~7% of population) you might consider using Blue / Yellow or something other than Red/Green.

I’ve found that sliding between only 2 colors is handy in a minority of situations, but perhaps your work is different. Even less used is the case where you decide to slide evenly between 4 or more colors. In the majority of cases it is much more useful is to specify the color value of the midpoint.

A much simpler variant of this is to pick specific colors for specific values. eg: China = Red, Britain = Blue etc. As seen in the simple CASE statement in Part 1 of this post.

 

Highlight tipping points - Color by specifying the distance from key value. (Value, Max, Min,Threshold)

More often I find myself using color to highlight extremes from a value. eg: Above/Below Budget, Above/Below Average, Above/Below 100%, Above/Below 0.  etc.

While is is possible to have many midpoint colors, (see Rainbow6), specifying 3 colors is the most used, moving from Min, Centre, Max. Because the human eye seems to comprehend & compare color gradients so well, I’ve found it best to use the same color increment for both sides of the centre. ie: If I have 10 steps to go from 0 (Green) to 100 (Yellow), then I’d prefer to use 10 steps to go from Yellow (100) to Red (200). So if the highest data value was only 133, as the range from Green-Yellow was 100, I’d never show Red. The value 133 would only be a shade of Orange, but that would permit comparison with 67 (100-33) which is the same distance from 100 but in the other direction.

So far that seems to be the preference of the vast majority of people who’ve used these reports. So that is the basis of the code samples shown here.

 

Ideas on how to set parameters for various applications:

  1. Only show transition between 2 colors.

    Set 4th parameter to equal either Max or Min extremes.
    Example: Dam Levels: range between 0 - 100%. They can’t be more nor less.
    =code.colorXYZ(Fields!DamLevel.Value, 100, 0, 0)
  2. Specify a Target (or middle value) & specify extremes.

    Example: Air Temperature: between -5 & 45 degrees Celsius. Perhaps you’d make the range wider but the idea is the colors are always the same, so you can compare from one report to the next. (like temperatures on the USA Today’s color weather map.
    =code.colorXYZ(Fields!Temp.Value, 45, –5, –5)
  3. Specify the Target & Limit the extremes with hardcoded values
    NB: If you do this, remember to modify the code to add the check for Data values outside of Max-Min range.

Example: Show Actuals or Budget.
The color range is from 80% – 120%, the middle color is 100. Below 80% is Red & Above 120% is Green.
=code.colorXYZ(Fields!PctProfit.Value, 1.2, 0.8, 1.0)

  1. Give the User control,
    Create Report Parameters & use them as the values for your color function.

    =code.colorXYZ(Fields!X.Value, Parameters!pMax.Value, Parameters!pMin.Value, Parameters!pThreshold.Value )
  2. Adjust to the Data's Minimum or Maximum values

    =code.colorXYZ(DataValue, Max(myField), Min(MyField), Avg(myField))
    1. Remember the Aggregate functions are very powerful. The 2nd parameter is the Data Group name. If you specify that you can have the conditional colors tailored to the specific range for each grouping set in your report.
    2. Unfortunately neither Reporting Services 2005 or 2008 supports Aggregates of Aggregates. Ie: Max( Sum(myfield) ). So if you need that as you occasionally do using the Matrix or Tablix items, Create a separate database query to calculate that & pass the results back either as a hidden parameter or simply as another data set. Eg:
      =code.colorXYZ( Sum(value), parmMax(SumValue), parmMin(SumValue), 0
  3. Show distance from average

    Highlight underperformers, by setting threshold to the average of the group.
    =code.colorXYZ(DataValue, Max(myField), Min(MyField), Avg(myField))
  4. Show distance from a fixed threshold
    Example: Highlight those who fail to meet a business metric; KPI or Quality level. ie: (Value, Max, Min, Threshold Constant)
    =code.colorXYZ(DataValue, Max(myField), Min(MyField), <Report Parameter or other database field>)

Warning: When you deal with aggregates pay very close attention to the 2nd parameter “Scope”.
In SQL2005 Tables it is optional, as if blank it automatically raises its scope to the parent. But it is not wise to get into this habit. If you leave scope blank in SQL2005 Charts, SQL2008 Tables & Charts you will get a single row. This is bad, none of your functions will display anything. So ALWAYS specify scope, If you haven’t got a clue what scope is, try using the name you called the dataset, or the name of the table or chart. eg:
=code.colorRainbow5(Fields!MAX.Value, Max(Fields!MAX.Value, "WorldTemps"), Min(Fields!MIN.Value, "WorldTemps") ) or use the name of any grouping level you created.

In a Chart it is often the value of the category group.

=code.ColorTwoLevelShade(Fields!RegionID.Value, CountRows("chart3_CategoryRegion"),RowNumber("chart3_CategoryRegion"))

image

 

I hope you found this part of the series useful & that it goes someway to improving your users ability to interpret their information & make better decisions, faster.

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.

Posted by davele | 5 Comments
More Posts Next page »
 
Page view tracker