How to make SSRS reports in a PerformancePoint dashboard “pop out” or open in a new window.

I’ve had this request from multiple clients.  The scenario is usually that they have a PerformancePoint dashboard that contains a mix of PerformancePoint Analytic Chart reports and Reporting Services reports.  The Reporting Services reports are usually just gauges or some kind of chart, but they want the ability to click on them and to show the underlying detail data.  The problem is usually that the detail data they want to see is far larger than the space allotted in the dashboard for the original SSRS gauge or chart…….so we need the detail data to open in a new window.

Unfortunately there isn’t really an option for “Open report in new window” in the settings (but that sure would be nice if anyone from Microsoft ever reads this).  So to make this happen, we’re going to need to write a little Javascript.

Assumptions for this walkthrough:

·         SSRS is in SharePoint integrated mode (although you can do this in Native mode as well)

·         SSRS is either 2008 or above.

The short version of this post is that you basically need to add the javascript shown below to the “Action” property of whatever it is your user is going to click on in the report. 

="javascript:void(window.open('http://mastvmbase/sites/TavisBIDemo/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/sites/TavisBIDemo/SSRS/BlogExampleReport.rdl', '', 'width=1000, height=800, top=0, left=0, resizable=yes'))"

Where:

Yellow = The URL to your report.

Green = The dimensions of the new window.

So the first thing we need to know is the URL to the report that we want to come up in our new window.  To get the URL we’re just going to browse to and open the report in SharePoint, and then copy it from the browser address bar….however you’ve probably got some stuff at the end that you don’t need.  For instance my report is called BlogExampleReport and the URL is:

http://mastvmbase/sites/TavisBIDemo/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/sites/TavisBIDemo/SSRS/BlogExampleReport.rdl&Source=http%3A%2F%2Fmastvmbase%2Fsites%2FTavisBIDemo%2FSSRS%2FForms%2Fcurrent%2Easpx&DefaultItemOpen=1

We want to remove everything after reportname.rdl so it looks like this:

http://mastvmbase/sites/TavisBIDemo/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/sites/TavisBIDemo/SSRS/BlogExampleReport.rdl

Now that we have our report URL we just add it to the Javascript as shown highlighted in yellow above.  Now we need to add our javascript to our report that the user will click on in the dashboard.  In my case, this report is a gauge.  So we’ll need to

1.      Right click on the Gauge in design mode, and select “Properties”

2.      Select “Action” from the Properties window.

3.      Select “Go to URL” as the action.

4.      Click the “Fx” button next to the “Select URL” field, and copy in our Javascript.

Click on the picture below to see each of the open screens.

clip_image002[4]

That should do it.  Just click OK on all the open windows and then deploy the report to test it.  NOTE: The report must be deployed in order for the Javascript to work.  It will not work in the preview window of your report designer. 

Now let’s say we want to pass a parameter from our original report to our report that opens in the new window.  We can also do this through the URL by adjusting our Javascript like so:

="javascript:void(window.open('http://mastvmbase/sites/TavisBIDemo/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/sites/TavisBIDemo/SSRS/BlogExampleReport.rdl&rp:p_ReportParameter1=ParameterValue', '', 'width=1000, height=800, top=0, left=0, resizable=yes'))"

Where:

Yellow = The URL to your report.

Purple = The parameter and value you’re passing in.

Green = The dimensions of the new window.

In the above example we’re passing a value of “ParameterValue” into our parameter named “p_ReportParameter1”.

It’s worth noting that you can also control several aspects of your report viewer toolbar by passing parameters in via the url.  There is an excellent post about doing so here:

http://blogs.msdn.com/b/prash/archive/2009/01/21/passing-url-report-parameters-to-reports-in-sharepoint-document-library-in-ssrs-2008.aspx

So I think that about wraps it up.  While it’s a little messy, and kind of a pain to manage through environments….the functionality is possible.  If you have several reports that need to be moved between dev/uat/prod, I highly suggest leveraging shared data sets to store your base report URL ei: “http://mastvmbase/sites/TavisBIDemo/_layouts/ReportServer/RSViewerPage.aspx?rv:RelativeReportUrl=/sites/TavisBIDemo/SSRS/” .  Doing so will allow you to change it in one place, instead of having to do so in each individual report when you deploy to a new environment.  Until next time, hope this helps.

I’m an MCITP in SQL BI 2008!

I recently took and passed the MCITP: Business Intelligence Developer 2008 certification (exam 70-452). Obviously I’m not allowed to talk specifically about the exam, but I did have a few thoughts on it after taking it.

For prep I used the Transcender practice exam pretty much exclusively. I’ve used them in the past, and you really can’t go wrong with their practice tests. The flashcards are great! Also the detailed explanations given for each question in the practice exam(s) are really handy. That said, the Transcender definitely is not exactly like the test, and there were a few questions I felt unprepared for. For the most part though it covers the areas you’ll need to know.

The biggest thing I noticed about the exam is that it just felt really dated (probably because it is, I shouldn’t have waited so long to take it). Since SharePoint 2010 came out, SharePoint is such a huge part of what a BI developer does these days. PerformancePoint, PowerPivot, Excel Services, etc, and the configuration(s) that go along with those services just weren’t covered. All mentions of SharePoint and PerformancePoint were still geared to SharePoint 2007 and WSS 3.0.

Another thing I noticed about the exam is that some of the questions were really geared more towards the DBA track in my opinion, particularly around the detailed coverage of db backups. I also would have expected to see a few more questions surrounding PerformancePoint/SSAS security, as that a topic that comes up almost every time I meet with a client…particularly around dynamic security.

Overall though, I’m really glad to have finally knocked out my first MCITP cert, and will proudly add it to my resume. In retrospect, I should have taken this test right after I took the MCTS BI test a little over a year ago, but hindsight is 20/20.

How to create a Linked Server to an Access DB in SQL Server

This tutorial will cover how to create and reference a Linked Server in SQL Server that allows you to query an Access database. So what is a “Linked Server”? A Linked Server is simply a reference in SQL Server to an outside data source (usually another instance of SQL Server, but in this case…an Access DB).

In this walkthrough I’m using SQL Server 2008R2 and the Access Database was created in Office 2010.

The first thing you need to do in order to reference an Access database is ensure that the proper drivers are in place, so SQL Server and Access know how to talk to each other. You’ll want to download the “Microsoft Access Database Engine 2010 Redistributable” and install it. The Download and installation instructions are located at http://www.microsoft.com/download/en/details.aspx?id=13255 . This will need to be installed on the computer that SQL Server is installed on. I found the install to be very straightforward, consisting of something like NextàNextà Nextà J. Make sure you get the correct version though (x86 vs. 64 bit).

Once installed, Open up SQL Server Management Studio (SSMS) and connect to your instance of SQL Server that you want to create the Linked Server on. Once there, navigate to Server Objects à Linked Servers à Providers à Microsoft.ACE.OLEDB.12.0 (as shown highlighted below)

clip_image001[6]

Right click on the “Microsoft.ACE.OLEDB.12.0” provider and select “Properties” to open up the properties window. Check the box for “Allow inprocess” as shown below and then click OK.

clip_image003[6]

Now all we have left to do is create our linked server. Right click on the Linked Servers folder in the Object Explorer in SSMS and select “New Linked Server”. This should open up a wizard to help us along. Enter the same information shown in the image below, making sure to select the “Microsoft Office 12.0 Access..blah blah blah” as your provider. You’ll also want to change the value of “Data Source” to be the location of your Access db.

clip_image005[6]

Once finished just click ok and if all has gone according to plan, you should see your linked server in the “Linked Servers” folder in SSMS (you might need to refresh the folder).

Now…how do we query our Access DB using T-SQL? As shown above, I named my Linked Server “TEST” and in the Access database that TEST references, there is a table called “People”. If I wanted to query that table I could do so like this:

SELECT * FROM OPENQUERY(TEST, 'SELECT * FROM People')

Now if I wanted to make this available to something like PerformancePoint, I could simply make the above query into a View and reference it like I would any other SQL Server table.

Well, I think that about does it. Hope this helps.

 

How to configure Windows Firewall to allow access to SQL Server

Having trouble connecting to SQL Server from a different PC? Read on.

This scenario assumes SQL Server 2008 R2 and Windows Server 2008. I ran into this problem for the umpteenth time the other day while trying to connect to a SQL Instance, so here’s a quick write up on how you might fix it. Now there are all kinds of reasons you might not be able to connect, but if you’re able to do things like

· Remote Desktop into the server that SQL Server is installed on just fine

· Have no problems connecting to the SQL Instance through SSMS when logged into the server that SQL Server is installed on

And if you’re getting an error somewhat similar to the following:

“A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) (Microsoft SQL Server, Error: 1326)”

You might want to take a look at your windows firewall settings in Windows Server and make sure that the ports that SQL Server talks over are open (port 1433 by default).

To open up the ports, you could just turn the firewall off all together, depending on your environment, this may or may not be an option….either way, it’s not something I suggest. It’s better to set up an exception in your firewall to allow communication over that port…..and this is how you can do it:

1. Log into the server that SQL Server is installed on and click on “Start” and then type Firewall.cpl in the search/run box. This should bring up the screen shown below. (Alternatively you could go to startàcontrol panel and then “check firewall status” under the “System and Security” section.)

clip_image002[4]

2. Click on “Advanced Settings” (highlighted in yellow above). This should bring up a new screen (shown below). Click on the “Inbound Rules” link highlighted in yellow.

clip_image004[4]

3. Next we’ll want to create a new inbound rule for our firewall by clicking “New Rule…” (highlighted in yellow below)

clip_image006[4]

4. The rest of the steps will be handled by a wizard. There are screen shots of each step. Important areas are highlighted in yellow.

clip_image008[4]

Port below is 1433 (if it's hard to read)

clip_image010[4]

clip_image012[4]

clip_image014[4]

clip_image016[4]

5. Once you’ve hit finish you should see your new rule in the “Inbound Rules” window as shown below.

clip_image018[4]

Depending on how you have your firewall setup, you may also have to configure an outgoing rule as well. To do so just follow the same steps above starting at step 2, only click “Outbound Rules” instead of “Inbound Rules”. Now this is not the end all fix for connection problems....and this assumes a few other things are in place, but it's an excellent starting point, and more often than not this is the problem from my experience. Hope this helps.

 

How to use a table-valued Parameter in SQL Server 2008

On occasion it's useful to pass an entire table of values to a stored procedure. In this walkthrough we'll take advantage of the new table-valued parameter available in SQL Server 2008. First let’s set our scenario. Let's say we have the following table:

clip_image001[4]

and we want to write a stored procedure that returns all the game titles based on one or more game systems we pass in. In the past, you'd usually write a split UDF and probably pass all the values in as a delimited list in the same parameter. While that works, if you've got a huge set you're passing, your performance can take a pretty big hit as it splits apart your string. Instead we can now pass an entire table. To do so we'll first need to create a definition for our table type like so:

CREATE TYPE dbo.GameSystemType AS TABLE

(GameSystemName varchar(50))

Once we've run this code we should now see our new user defined table type in the SSMS object explorer as seen below.

clip_image002[4]

With our table type defined lets create our stored procedure that uses our User-Defined Table Type as a parameter like this:

CREATE PROCEDURE usp_GetGames

(@p_GameSystem dbo.GameSystemType READONLY)

AS

BEGIN --proc

      SELECT

            vg.GameTitle,

            vg.GameSystem

      FROM

            VideoGames vg

            INNER JOIN @p_GameSystem gs

                  ON vg.GameSystem = gs.GameSystemName

END --proc 

As we can see our procedure has only one parameter named @p_GameSystem and its type is that of our User-Defined table. The rest of our procedure just selects all the game titles and game systems that are equal to whatever game systems are in our @p_GameSystem parameter. It does so by INNER JOIN’ing to our table parameter (thus only giving us results that have a match in our table parameter)

Now when we call our procedure we'll need to declare and load our parameter ahead of time like so

--declare our table

DECLARE @p_GameSystemTable AS GameSystemType

--load some values into it

INSERT INTO @p_GameSystemTable SELECT 'Nintendo'

INSERT INTO @p_GameSystemTable SELECT 'Playstation'

--call the proc and pass in our table

EXEC usp_GetGames @p_GameSystem = @p_GameSystemTable

In our case we'd get the following results from our table:

clip_image003[4]

Just like that we've passed multiple values in the same parameter, and didn't have to do any string splitting or parsing....nice. This was obviously a pretty simplistic example for demonstration purposes. My hope is they make the integration of the table-valued parameters a little more robust with Reporting Services (SSRS) in the future for things like multi-select parameters. Unfortunately there's still quite a bit of scripting involved in using this with SSRS due to the fact you have to declare the table type and load it ahead of time, and there's no mechanism other than writing code to do that in SSRS at the moment. Hopefully that changes in the future.

 

Using T-SQL UNION and UNION ALL

The UNION statement does pretty much exactly what it says, It takes two (or more) result sets and combines (or UNIONs) them together into one result set. In order to UNION the result sets together there are a few things you'll want to check first.

· Each result set must return the same amount of columns. - So if the first query returns 5 columns....all other UNIONed queries must also return exactly 5 columns, otherwise you'll end up with an error.

· Columns names for the UNIONed result set are defined in the first SELECT statement of the UNION query. - So if you want your first column to be called "Col1" in the result set, make sure you have it named as such in the very first select statement.

· You can have one and only one ORDER BY statement in a UNION. The ORDER BY statement must appear in the final select statement of the UNION query, and will order all data across the entire set.

In this example I'm going to use 2 tables named "TableA" and "TableB". Both of the tables have one column in them named "ID" that contains integer values. "TableA" will contain all even number from 1-10, and "TableB" will contain all odd numbers 1-10. In addition to that, each table will contain all numbers from 1-5. To recap:

TableA contains the following values (1, 2, 3, 4, 5, 6, 8, 10)

TableB contains the following values (1, 2, 3, 4, 5, 7, 9)

If we wanted to write a query that would return all DISTINCT values from each table in one result set, we could do so using the UNION operator like so:

SELECT
      a.ID
FROM
      TableA a
UNION
SELECT
      b.ID
FROM
      TableB b
ORDER BY
      ID

The results of this query would look like this:

ID

-----------

1

2

3

4

5

6

7

8

9

10

Which is exactly what we expect. An important note here is that the ORDER BY statement only appears once at the very end of our query (as mentioned before). Without the ORDER BY statement, we couldn't guarantee the order of our results.

While the UNION statement returned all the DISTINCT values from each of our tables, let's suppose we had a need to see every value all in one set, even the values that were repeating. We can accommodate such a need by simply using "UNION ALL" instead of just UNION, as seen below

SELECT
      a.ID
FROM
      TableA a
UNION ALL
SELECT
      b.ID
FROM
      TableB b
ORDER BY
      ID

The results of this query would be as follows:

-----------

1

1

2

2

3

3

4

4

5

5

6

7

8

9

10

We now see every single row in each of the SELECT statements, even if there are duplicates.

While we've only been using two SELECT statements in our examples, you can UNION just about as many SELECT statements together as you want (or at least as many as would be practical) as long as they meet the criteria we discussed at the beginning of this article. So for instance if we wanted to add a third table our query might look something like this:

SELECT
      a.ID
FROM
      TableA a
UNION
SELECT
      b.ID
FROM
      TableB b
UNION
SELECT
      c.ID
FROM
      TableC c
ORDER BY
      ID

I'd say that probably wraps up our use of UNION. Hopefully someone finds this helpful, and as always if you've got any questions feel free to shoot me an email at the address on my contact page.

 

How to reference a Stored Procedures name dynamically

When executing custom logging from within a procedure, you almost always want to include the name of the procedure that actually executes the logging action, be it an error, row counts, specific events or whatever it is you're wanting to keep tabs on. A great way of getting the procedure name without having to hardcode it (horrible idea) into the procedure is to use @@PROCID and OBJECT_NAME()to retrieve the name of the procedure. This way you never have to worry about a hardcoded "procedure name" value falling out of sync with the actual name of the procedure executing the logging statement. As an example, the following code creates a procedure named "usp_ProcIDTest" and then calls it.

CREATE PROCEDURE usp_ProcIDTest

AS

SELECT OBJECT_NAME(@@PROCID) 'ProcName'

GO

EXEC usp_ProcIDTest

The result of this procedure being called would be the procedures name

clip_image001[4]

While a procedure that returns its own name isn't particularly useful, one can see how this would be pretty handy if we were making an insert into our logging table. You could even create a separate logging procedure that you just pass the @@PROCID value into....I'll leave that ball in your court though.

 

Understanding Join Types

One of the first hurdles in understanding for someone trying to learn T-SQL is usually what the different Join types mean, and when to use them. Specifically the differences between Inner and Outer Join as these are the types most commonly used. If database mastery is what you seek, your SQL-fu will never be good enough until you know all the different join types and how they differ from each other. So right off the bat let’s just thow their names out there so you can get used to seeing them:

· Inner Join

· Left Outer Join

· Right Outer Join

· Full Join

· Cross Join

Ok, so that’s not too bad, there are only 5 different types of joins. So let’s set up an imaginary scenario that we can use to talk about them. We’re going to have one table named “System” that contains video game systems, and one called “Games” that contains related games for the systems. We’ll structure the tables so that there is a 1 to many relationship between our two tables like so:

clip_image001[4]

I realize in reality this is probably a Many to Many relationship, but let’s not get ahead of ourselves. For the sake of simplicity in this example let’s assume games are mutually exclusive to systems, meaning they can only belong to 1 and only 1 system. So if you want Super Mario Brothers…you’ll have to buy a Nintendo etc.

Now let's load up our tables with some example data. For our System table we'll have the following data:

clip_image002[4]

Now for our Games table (below) data let's add the following:

clip_image003[4]

So these two tables are related based on the ID column in the System table and the SystemID column in the Games table. For example the Atari 2600 in the System table has an ID of 1. If we Look for rows with a SystemID of 1 in the Games table, we'll see that the first two rows match this criteria. As we go through our Join examples it will be helpful for you to know a few things about this data ahead of time

1. The Atari 2600 has 2 games and is the only system to have more than 1 game in the Games table.

2. Playstation 2 has no games at all in the Games table.

3. All other systems have exactly 1 game in the Games table.

Now that we've gone through setting up our scenario let's start talking about our join types.

INNER JOIN

An inner join will only show you ONLY the rows that match between two tables. It's also possible to have repeating values if a row has more than one match. let's take a look at an example query using Inner Join and its result set.

SELECT

      s.Name,

      g.Name 'Game Name'

FROM

      [System] s

      INNER JOIN [Games] g

            ON s.ID = g.SystemID

the above query would have the following results.

clip_image004[4]

There are a few things to note here. As we mentioned earlier, Inner Join will repeat a row if it has multiple matches. You can see this in action if you look at Atari 2600. It gets repeated because two matches were found in the Games table. The second noteworthy item involves the Playstation 2 System. It doesn't appear in our above result set at all because it didn't have any matches in the Games table. That's very important, if your results are missing data you expected to see, you may have eliminated it from the result set by using an Inner Join.

An easy way to think about Joins is to use a Venn Diagram.

clip_image005[4]

If the circle on the left represented all the rows in the System table, and the circle on the right represented all the rows in the Games table. The rows that an Inner Join would return would be where the two circles intersect or have a match. This area is highlighted green in the Venn Diagram above.

LEFT OUTER JOIN

Left Outer Join will allow you to see ALL the rows from one table AND any matching rows from another table. If there are no matches then NULL will be displayed.

Q: So how do I know which of the two tables will have all of its values shown?

A: Whatever table gets listed first in the from clause is the table that gets all its values displayed. You can think of it quite literally as the table furthest left if you were to write your query all on one line.

let's take a look at an example query using Left Outer Join and its result set.

SELECT

      s.Name,

      g.Name 'Game Name'

FROM

      [System] s

      LEFT OUTER JOIN [Games] g

            ON s.ID = g.SystemID

the above query would have the following results.

clip_image006[4]

We see that our results are almost exactly the same. The only difference is now we see our Playstation 2 System, where we didn't before. Note that the "Game Name" is NULL for Playstation 2 since there are no matching values. Note also that Atari 2600 is still repeated because it found two matches. So if it's imperative that all values in a specific table be displayed in a result set, you'll want to make sure to use Left Join any time you join a table to it. To go back to our Venn Diagram, if we wanted to adjust it to represent a Left Join, it would look like this.

clip_image007[4]

We've now shaded in all of the System circle, because no matter what, everything in the System table is going to appear in our result. Again, this is because we Left Joined the games table to the System Table.

RIGHT OUTER JOIN

Right Outer Join does pretty much the same thing as Left Outer Join, only in a different order. In general I don't see people use RIGHT OUTER JOIN very often, and I myself never use it. Right Outer Joins can be rewritten as Left Outer Joins and vice versa, by simply switching the order the tables are listed in. If we were to simply replace Left with Right in our last query like so:

SELECT

      s.Name,

      g.Name 'Game Name'

FROM

      [System] s

      RIGHT OUTER JOIN [Games] g

            ON s.ID = g.SystemID

Our Venn Diagram for this query would look like this.

clip_image008[4]

We would now be showing ALL the values from the Games table, and any matching values from our System table. If a game didn't belong to a system, the system would appear as NULL. (this doesn't happen in our test data however, because all games belong to a system) .

As mentioned before, we could make our Right Outer Join query return Exactly the same as our previous Left Outer Join Query by switching the order the tables appear in like so:

SELECT

      s.Name,

      g.Name 'Game Name'

FROM

      [Games] g

      RIGHT OUTER JOIN [System] s

            ON s.ID = g.SystemID

FULL JOIN

A Full Join is like doing a Left Outer Join and Right Outer Join at the same time. I know....... I probably just blew your mind right out of your skull huh?....like trying to imagine what 4D looks like. So now all values from both tables you're joining will appear in the result set, and if they don't have a match on the other side of the join, they'll just display NULL. If you Understood Left and Right Outer Joins, Full Joins should be pretty easy to understand. Their Venn would look like this:

clip_image009[4]

CROSS JOIN

Last but not least, a Cross Join will take the each row in the first table and match it up with every row in the second table. It does this by performing a Cartesian Product on the two tables. Since all rows from the first table are going to be matched to all rows from the second table and vice versa, there's no need to specify an ON clause in your queries FROM statement when using a Cross Join. Cross Join results get very big very fast, If we were to cross join our test data tables we'd already be up to 49 rows, so be careful. It's pretty rare to find a use for a Cross Join....although it does happen.

Well, hopefully that sheds a little light on the whole JOIN situation for someone starting out.

 

SSIS Best Practices

Just read this article over at www.sqlcat.com, and thought it was worth making a post about. There are just so many different ways you can get from A to B in SSIS......or in this case E to L perhaps?............*crickets*....hello....is this thing on? Of course the #1 thing on the list: Integration services is a memory pipeline, so keep it in memory (most of the time anyway). That means cease your staging table ways of the past, and embrace the tools available. Have a look, you'll probably learn something: http://sqlcat.com/top10lists/archive/2008/10/01/top-10-sql-server-integration-services-best-practices.aspx