Using SSMS to change the Edit TOP Rows option

SQL Server 2008 Management Studio has an option to Edit the Top 200 Rows. Just Right Click on the Table and you get the following options:

image

If your table contains many columns, opening 200 rows to edit them would be slow to execute. However not many know that this number can changed using a simple setting.

So let us say we want to edit only the TOP 5 Rows. A quick way to do this would be to go to Tools > Options > SQL Server Object Explorer and change the ‘Value of Edit Top <n> Rows Command to 5

Now when you Right Click the Table, you see the option to Edit only TOP 5 rows

image

A very simple tip, but known to many!

Enable and Disable All the Triggers in a SQL Server Database

A database developer recently asked on the MSDN forums for a quick way to enable and disable all the triggers in a SQL Server 2005/2008 database. In my opinion, the quickest option is to use the undocumented stored procedure sp_MSforeachtable

To Disable All the Triggers

sp_MSforeachtable "ALTER TABLE ? DISABLE TRIGGER ALL"

To Enable All the Triggers

sp_MSforeachtable "ALTER TABLE ? ENABLE TRIGGER ALL"
 

Similarly to Enable and Disable all the Constraints, use this query:

sp_MSforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL"
sp_MSforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL"

List All Tables and Views with the XML Data Type in SQL Server 2005/2008

Here’s a simple way of listing all tables and Views with the XML datatype using the INFORMATION_SCHEMA views.

SELECT DISTINCT col.TABLE_NAME, col.COLUMN_NAME, col.DATA_TYPE  
FROM INFORMATION_SCHEMA.COLUMNS as col
WHERE col.DATA_TYPE = 'xml'

As given in the Books Online “Information schema views provide an internal, system table-independent view of the SQL Server metadata. Information schema views enable applications to work correctly although significant changes have been made to the underlying system tables. The information schema views included in SQL Server comply with the ISO standard definition for the INFORMATION_SCHEMA.”

OUTPUT

image

Working With Report Model in SSRS – Part III

In last 2 articles Working with Report Model Part I and Working with Report Model Part II, we discussed overview of report model and how to create report model with the help of designer. In this article, we will create Report with Report Builder 2.0 based on the Report Model created in the previous article (Working with Report Model Part II)

Report Builder 2.0 can be downloaded from here

1. For working with Report Builder 2.0 go to Start > All Programs > Microsoft SQL Server 2008 > Report Builder 2.0

2. Create a New Report > Select table or matrix report > the connection to data source screen will be shown. Click on Browse (ensure you have given proper URL for report server) > in select data source it displays folders for models > Select “Report Model Demo” > click on Next.

3. A Design query screen will be provided as follows:

image

4. Under Entities, if you double click on ‘Customer’, all the entities will be automatically added to drag and column fields area. But we will not be working with only Customer.

5. Select Product from entities; double click “English Product Name” from fields. You will see that once we select Product, only related entities to Product are displayed in entities. Select Product SubCategory and double click on “English Product Subcategory Name” so as to get selected. Select Product Category and double click on “English Product Category Name”.

6. Select Internet Sales from entities. Double click on “Total Unit Price” and “Total Unit Quantity”.

7. Select Order Date from entities. Double click on “Calendar Quarter Desc”, “Calendar Year Desc” and “Month Name” and click on Next.

8. Drag and drop the fields so that the screen looks as follows:

image
and click on Next.

9. Keep the default settings for Choose the layout screen and click Next.

10. Select the required style and click Finish.

11. After doing certain changes like changing names of some columns, providing format for Unit Price the report looks as follows:

image

And there you have your first report created using a custom Report Model in Report Builder 2.0

Working with Report Model in SSRS - Part II

Creating Report Model using BIDS (Business Intelligence Development Studio)

In Part 1 of this series, Working With Report Model in SSRS – Overview - Part 1, we discussed the Report Model, the items in Report Model and its uses. Let us now see how a Report Model can be created with the Report Model Designer. Report Model Project is provided as a template with BIDS. With this tool you can do certain customizations to the Report Model items as required.

1. Select Report Model Project template and give it a name - “Report Model Demo”

2. Create a Data Source named “Adventure works DW 2008” pointing to AdventureWorksDW2008 database. It can be downloaded from following link http://msftdbprodsamples.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=18407

3. Create a Data Source View (DSV) with following tables

clip_image002
namely “Adventure Works DW2008”

4. Before creating model let us do the following changes to DSV. Change the friendly names of the tables so that they look as follows:

clip_image004

5. Add 3 calculated fields as follows :

- Calendar Quarter Description: 'Q' + CONVERT(CHAR (1), CalendarQuarter) +' '+ 'CY ' +
CONVERT(CHAR (4), CalendarYear)
- Calendar year description: 'CY '+ CONVERT(CHAR (4), CalendarYear)
- MonthName: EnglishMonthName+' '+ CONVERT(CHAR (4), CalendarYear)

6. In the solution explorer, right click on Report Model and select Add New Report Model which will start the wizard for model creation. It is based on the DSV created in the last step.

7. Keep default settings for Report Model Creation Rules, Collect Model Statistics, name for the model and click on Run and finally Finish.

8. Remove attributes such as Spanish Education, French Education, Spanish Occupation, French Occupation from Customer entity. You will observe that Internet Sales and Geography are added to this entity as Roles. If you select properties for any one you will see the foreign key relationship between the two specified in Bindings. Similarly you can remove descriptions from Product.

9. You can also remove attributes from Total Children like avg, min and max. You can change the alignment of numeric fields to Right.

10. Right click on “Report Model Demo” in the solution explorer and select properties. Check if the TargetServerURL is correct.

In case of a named instance of SQL Server, it should be http://<machine name>/ReportServer_<instance name>.

If the port number is other than 80 it should also be included as follows http://<machine name>:8080/ReportServer_<instance name>. Machine name can be replaced by localhost.

11. Deploy this Report Model

12. Start Report Manager by giving the URL. In case of named instance of SQL Server it should be http://<machine name>/Reports_< instance name> and verify that the newly created model is available in Models Folder. After installing Report Builder we can specify the report builder setting within which report server URL can be provided.

In next article we will discuss how to create a report using this report model with the help of Report Builder 2.0

Working with Report Models in SSRS - Overview – Part I

When we are creating reports with the help of SSRS (SQL Server Reporting Services) using BIDS (Business Intelligence Development Studio), we are dealing with predefined report formats. Sometimes it is required to create certain reports on the fly. We do not have a set format for these reports. These report formats are required to be created as and when required by the client. For this reason, a very important feature has been provided called ‘Report Builder’ in SSRS. With the help of Report Builder, ad-hoc reports can be created. These reports are based on Report Models.

Business users who want to create reports on demand may not be familiar with the physical data source schemas of the databases. Report Model provides user friendly and easy to understand entities based on which report creation becomes easy. These people may also not be familiar with the designer for creating reports.

Report Model thus becomes a prerequisite of Report Builder, when working with Report Builder 1.0. However with Report Builder 2.0, it is no more a prerequisite, as we can create ad-hoc reports without Report Models created previously. A report model contains metadata of data source and the relationships within. This metadata is in the form of SMDL (Semantic Model Definition Language). This is an XML based way of presenting model items. Models can be created with Report Model Template provided by BIDS. Models can also be created with Report Manager or Microsoft Office SharePoint Server 2007, but using BIDS provides maximum flexibility. You can base the model on Analysis Services cube if required. If we change the cube later, we need to regenerate the model. Report Model on Analysis Services cube cannot be created using designer.

Report Models comprise of following components

1. Entities: similar to objects in tables (entities have attributes and roles)

2. Attributes : similar to columns in tables

3. Roles: specifies relation between entities

4. Folders: used to organize entities and perspectives, certain model items can be grouped

5. Perspectives: subset of model, useful when models are very large, perspectives in themselves can contain entities, roles, folders etc.

In next article we will discuss how a model can be created using BIDS.

How To Find the ASCII Value of each character in your String – SQL Server

Here’s a simple query that lists the ASCII Value of each character in your string in SQL Server

DECLARE @counter int = 1;
DECLARE @colString varchar(10) = 'AA%#& ';

WHILE @counter <= DATALENGTH(@colString)
BEGIN
SELECT CHAR
(ASCII(SUBSTRING(@colString, @counter, 1))) as [Character],
ASCII(SUBSTRING(@colString, @counter, 1)) as [ASCIIValue]

SET @counter = @counter + 1
END
GO

Here we are using the ASCII function to list the ASCII values of each character

OUTPUT

image

This function can be very useful to find and replace characters like Tabs, LineFeed etc. that may get inserted in a string. Check the last row in the screenshot above. It is the Tab Control Character with ASCII 9.

In case you want to remove the Tab Character, use this query

SET @colString = REPLACE(@colString, CHAR(9), '')

Using REPLACE to remove characters from Selected positions in your SQL Server column string

I faced a simple but challenging issue recently. A table had a nvarchar column with data in the following format: 91-39-45-3845

The Column was expected to be in the format 913945-3845 with the first two hyphens (-) removed.

Here’s how the requirement was achieved:

DECLARE @TT table
(
ItemDescription nvarchar(20)
)

INSERT INTO @TT VALUES('91-39-45-3845')
INSERT INTO @TT VALUES('45-24-85-5643')
INSERT INTO @TT VALUES('57-54-92-8835')

SELECT * FROM @TT

UPDATE @TT
SET ItemDescription = REPLACE(SUBSTRING(ItemDescription, 1, 7), '-', '')
+ SUBSTRING(ItemDescription, 8, DATALENGTH(ItemDescription))

SELECT * FROM @TT

OUTPUT:

Before the query was run

image

After the query was run

image

Find out the Tables Modified in a SQL Server Database in the Last ‘N’ Days

Here’s a simple SQL Server 2005/2008 T-SQL query that lists the tables of the AdventureWorks database that were modified in the last 30 days:

USE AdventureWorks;
GO
SELECT name AS [TableName],
SCHEMA_NAME(schema_id) AS [Schema],
modify_date as [ModifyDate]
FROM sys.objects
WHERE modify_date > GETDATE() - 30
and type_desc = 'USER_TABLE'
GO

OUTPUT

image

Note: To list all the objects like Constrains, Triggers etc of the AdventureWorks database that were modified in the last 30 days, just remove this line and type_desc = 'USER_TABLE' from the query and execute the query again.

Exploring Additional Multi Dimensional Expression (MDX) Functions in SQL Server Analysis Services – Part 3

I recently wrote two articles on MDX in SQL Server Analysis Services

Exploring MDX (Multi Dimensional Expression) in SQL Server Analysis Services

Exploring Additional Multi Dimensional Expression (MDX) Functions in SQL Server Analysis Services – Part 2

This is the third and final part of the series and we will explore some additional functions of MDX:

1. IIF functions
returns one of the possible two values in a logical test. It can return either a string or numeric value.

WITH MEMBER MEASURES.[IIF Value] AS
IIF([Measures].[Order Quantity]>1000
, "Qty High", "Qty Low")
SELECT {[Measures].[Order Quantity],MEASURES.[IIF Value]} ON 0,
[Order Date].[Calendar].[Calendar Quarter].MEMBERS ON 1
FROM DemoCube

In this query, we are displaying whether the quantity is low or high, according to the value for Order Quantity.

image
We can change the condition if required.

2. Let us use IIF with string data

WITH MEMBER [IIF String] AS
IIF([Product].[Product-Category]=Bikes
, "Common", "not common")
SELECT {[Measures].[Sales Amount],[IIF String]} ON 0,
[Product].[Product-Category].[Product Category Key].MEMBERS on 1
FROM DemoCube

3. Let us add a calculated member. The following query creates percent by using MDX and displays results:

WITH MEMBER Measures.[Percent] AS
([Measures].[Sales Amount],[Product].[Product-Category].CurrentMember)
/([Measures].[Sales Amount],[Product].[Product-Category].[All]),
FORMAT_STRING="Percent"
SELECT Measures.[Percent] on 0,
NON EMPTY [Product].[Product-Category].[Product Category Key].members on 1
from democube

This calculation can be kept for further usage if it is added from BIDS (Business Intelligence Development Studio) as follows

image

Here we can give the format string to percent, if required. Later it can directly be used in MDX as follows:

SELECT [Measures].[Percent Sales] ON0,
NON EMPTY [Product].[Product-Category].[Product Category Key].members on1
fromdemocube

This will give the same result as the previous query, with the difference that we already have a calculated field.

4. Let us discuss different ways of using the COUNT function. The following query returns the number of hierarchies in a cube:

WITH MEMBER MEASURES.[Count] AS
dimensions.count
SELECT Measures.[Count] ON 0
FROM DemoCube

5. The following query returns number of levels in the product categories:

WITH MEMBER measures.[Count] AS
[Product].[Product-Category].Levels.Count
Select Measures.[Count] ON 0
FROM DemoCube

6. The following query counts the number of cells in a set of members that consists of children of a category:

WITH MEMBER measures.X AS
[Product].[Product Category Key].children.count
SELECT Measures.X ON 0
FROM DemoCube

We can exclude non empty cells in the following manner:

WITH MEMBER measures.[Count] AS
Count
([Product].[Product Category Key].children, EXCLUDEEMPTY)
SELECT Measures.[Count] ON 0
FROM DemoCube

7. Let us look at parallel period now.

In order to display the data in a more meaningful manner, I have added the following calculated fields in DSV (Data Source View):

Calendar Quarter Description: 'Q' + CONVERT(CHAR (1), CalendarQuarter) +' '+ 'CY ' +
CONVERT(CHAR (4), CalendarYear)


Calendar year description: 'CY '+ CONVERT(CHAR (4), CalendarYear)
and MonthName: EnglishMonthName+' '+ CONVERT(CHAR (4), CalendarYear)

I changed the time dimension to incorporate these changes as follows:

Attribute English Month Name

Key columns collection is as shown below:

image

with Name column pointing to newly created MonthName

Similarly Calendar Quarter key columns is as follows

image

with the Name column pointing to a Calendar Quarter description.

Calendar year’s name column points to Calendar Year Description

A parallel period returns a member from prior period in the same relative position as a specified member.

Two more properties need to be changed for English month name as follows:

OrderBy: AttributeKey
OrderByAttribute: Month Number of year

If we forget these settings, the order will be on character month and which will be misleading/

The following query returns parallel period for the month of July 2002 with a lag of 2 periods based on quarter level which is January 2002

SELECT ParallelPeriod ([Order Date].[Calendar].[Calendar Quarter]
, 2, [Order Date].[Calendar].[English Month Name].&[2002]&[July])
ON 0
FROM DemoCube

A similarly query

SELECT ParallelPeriod ([Order Date].[Calendar].[Calendar Year]
, 1, [Order Date].[Calendar].[Calendar Quarter].&[2002]&[2])
ON 0
FROM DemoCube

gives us result as Quarter 4 and year 2001. If we change the lag to 2 periods, we may not get the result in this case, as the starting year for the data is 2001

8. Parallel period is similar to Cousin function so let us discuss Cousin function.

This function returns child member with same relative position under a parent member as the given child member.

The following query displays cousin of 3rd quarter of year 2001 based on year level in 2002, which gives quarter 1 in 2003

SELECT Cousin
( [Order Date].[Calendar].[Calendar Quarter].&[2001]&[3]
,[Order Date].[Calendar].[Calendar Year].&[2002]
) ON 0
FROM DemoCube

In these 3 articles, we discussed what is MDX, how queries can be used to view data from multi dimensional cubes and different clauses for MDX queries. We also discussed some functions available with MDX (sum, avg, prevmember, count,min, max, topcount) and how formatting can be provided, so that the result looks user friendly. We discussed how calculated members can be created and displayed. We also discussed some more functions like IIF, Parallel Period and Cousin.

Exploring Additional Multi Dimensional Expression (MDX) Functions in SQL Server Analysis Services – Part 2

SQL Server Analysis Services - Additional functions in MDX

In my previous article Exploring MDX (Multi Dimensional Expression) in SQL Server Analysis Services, we discussed how to write simple queries with MDX to query multi dimensional cubes. In this article, we will continue with the same example and add some more functions.

We will also discuss how to format the data when using MDX.

1. Let us see how to format the data

WITH MEMBER Measures.[Order Quantity Formatted] AS
([Measures].[Order Quantity] ),FORMAT_STRING="#,##,#.00"
SELECT NON EMPTY {Measures.[Order Quantity Formatted]
} ON COLUMNS,
NON EMPTY [Product].[Product Category Key].MEMBERS on ROWS
FROM
DemoCube

The result looks as follows:

image

If we change the format string to ="#,##,#.##” the result is as follows

image

2. Let us add a time dimension to the cube. Open the previously existing DSV (Data Source View). Right click on the empty area and select Add/Remove tables > add DimTime tab. Give the friendly name as ‘Time’.

3. Right click on Dimensions in Solution Explorer > select New Dimension and select the radio button for Use Existing Tables. In Specify Source Information dialog, select as shown below:

image

Keep the name for the dimension as Time and click Finish

4. Double click on the cube in Solution Explorer and select Cube Structure tab. Right click on the empty area for Dimensions and add Time dimension as a new Cube Dimension. We see that all the three dates - ship date, order date and due date are added.

5. Let us add more attributes to this dimension. Select Time Dimension from the Solution Explorer > drag and drop EnglishMonthName, CalendarQuarter, CalendarYear from Data Source View into attributes.

6. Create a hierarchy named Calendar with Calendar Year - Calendar Quarter – English Month name – Time Key. Change the name column for the Time Key to FullAlternateDateKey and build and deploy. If we browse in BIDS we see data as shown

image

7. Let us use this in a MDX query now.

SELECT [Measures].[Order Quantity] ON 0,
TOPCOUNT ([Order Date].[Time
Key].MEMBERS,5,[Measures].[Order Quantity]) ON 1
FROM DemoCube

will give the result as shown below:

image

8. Now let us use the WHERE clause. The WHERE clause determines which dimension or member is to be used as a slicer. A query can have multiple axes, but when a query has 3 axes we will not be able to display it (in SSMS). For this the WHERE clause has been provided.

SELECT [Measures].[Order Quantity] on COLUMNS,
[Product].[Subcategory].[Product Subcategory Key].&[2]
on rows
FROM
DemoCube
WHERE ([Order Date].[Calendar].[Time Key].[2001-08-01 00:00:00.000] )
We can also have more than one member in WHERE
SELECT [Measures].[Order Quantity] on COLUMNS,
[Product].[Subcategory].[Product Subcategory Key].&[2] on rows
FROM
DemoCube
WHERE ([Order Date].[Calendar Year].&[2001],
[Order Date].[English Month Name].&[August])

9. Let us see how certain functions can be used in calculated members

WITH MEMBER Measures.Total AS SUM
( { [Order Date].[Calendar].[Calendar Year].&[2001]
, [Order Date].[Calendar].[Calendar Year].&[2003]},
[Measures].[Sales Amount])
SELECT Measures.Total ON 0
,NON EMPTY [Product].[Product-Category].[Product Category Key].Members ON 1
FROM DemoCube

In this query we are using function SUM where sum of two years 2001 and 2003 for Sales amount is calculated. The result is as shown.

image

Similarly we can find average by using AVG function.

10. Following query returns maximum quarterly sales for each category

WITH MEMBER Measures.[Max Value] AS Max
([Order Date].[Calendar].[Calendar Quarter]
, [Measures].[Sales Amount]
)
SELECT Measures.[Max Value] ON 0,
NON EMPTY [Order Date].[Calendar].[Calendar Quarter] *
[Product].[Product-Category].[Product Category Key].MEMBERS
ON 1
FROM DemoCube

Max can be replaced by min if required.

11. Let us see following query which uses ‘PrevMember’ which returns previous member in the same level as the specified member

This query returns 2002 as the previous year for 2003

SELECT
[Order Date].[Calendar].[Calendar Year].&[2003].PrevMember
ON 0
FROM DemoCube

Similarly NextMember can be used.

12. Following query returns user name of the user that is executing the query

WITH MEMBER Measures.[Name] AS UserName
SELECT Measures.[Name] ON COLUMNS
FROM DemoCube

In this article we discussed how the WHERE clause works in MDX. We also discussed some functions like topcount, sum, avg, min, max, prevmember etc.

In next article we will discuss how iif and count functions can be used in MDX. We will also discuss how parallel period works.

Exploring MDX (Multi Dimensional Expression) in SQL Server Analysis Services

Introduction to MDX

Multi Dimensional eXpression (MDX) is a language created to allow the users to work with multi dimensional data in Microsoft SQL Server Analysis Services. It works as a query language with OLAP (Online Analytical Processing) cubes. We can also use it to create calculated members or use the various functions provided which can be used to query data.

Differences in SQL and MDX

If you are a little familiar with SQL (Structured Query Language), you may feel there is some similarity with MDX in some aspects. The SELECT clause, FROM clause and WHILE clause are similar with SQL and MDX. MDX provides various ways with which a cube can be queried - it provides different functions.

With MDX we can even create, modify and delete cubes if required.

MDX infrastructure

MDX works with multi dimensional data where we mostly have more than 2 dimensions. A dimension is a collection of related objects. These objects are called as attributes which provide information about fact data. For example when we consider attributes for a customer dimension they can be customer name, type of customer (low, ordinary or priority), location for customer etc. If we need detailed information like – ‘in a specific month all the transactions for a particular customer’ ,we need the details coming from the fact tables. Cubes contain different dimensions on which users base the queries. For example the dimension can be the type of customer, location of customer or time period.

How MDX queries data

To identify data, MDX uses reference system. This reference system is based on tuples. A tuple can identify a cell uniquely. Like we reference a cell in a spreadsheet by giving the column followed by the row number, we can also reference the tuple. The similarity ends here as there can be multiple dimensions in a cube as against to only rows and columns in a spreadsheet. A tuple can also be referenced by considering a default member. This default member is [All] member for every hierarchy in a cube.

We will start by creating a cube on adventureworksDW database.

1. Create Analysis Services project and name it MDXDemo

2. Add a new data source in it, which directs to Adventure Works DW database namely ‘AdventureWorksDW’

3. Add a new Data Source View (named Adventure Works DW) which consists of tables DimProduct, DimProducSubCategory, DimProducCaetgory, DimCustomer and FactInternetSales. Change friendly names for tables to as shown in figure:

clip_image002

4. Create a cube with default settings but selective measures as Order Quantity, Unit Price, Sales Amount and Internet Sales Count. Give cube name as DemoCube.

5. Go to the Properties of the project (MDXDemo) > select Deployment tab and enter server name. (if you are working with default instance, you can keep the name provided by default i.e. localhost)

6. After successful deployment, open SSMS and connect to Analysis Services to work with MDX queries.

7. Create a new query, connect to MDXDemo database

Enter following MDX query:

SELECT FROM DemoCube

In this case default member for Order Quantity is displayed as 60938

Enter the query as

SELECT [Measures].[Order Quantity] ON 0
FROM DemoCube

will also give the same result. (0 can also be replaced by COLUMNS) which is the axis.

8. Let us add one more measure as follows:

clip_image004

In this case we see two measures Order Quantity and Sales Amount on Columns

Let us change the default measure. Go to Cube Structure tab in MDXDemo project in BIDS (Business Intelligence Development Studio). Right click on Sales Amount and click Move Up till it becomes first measure. Redeploy the cube and again enter the query

SELECT FROM DemoCube

Now the value shown is different. Let us format this to show only 2 digits after decimal. Enter the FormatString as #,###,##.## and see the difference now.

The default measure can also be changed by MDX as follows

ALTER CUBE DemoCube
UPDATE DIMENSION
Measures, DEFAULT_MEMBER=[Measures].[Order Quantity]

In this case we are again changing the default measure back to Order Quantity

9. Go to DSV (Data Source View), right click on Customers and add a named calculation with name as FullName and expression as FirstName + ‘ ‘ + LastName. Double click on Customers dimensions and specify FullName as NameColumn (so as to display name and not number).

10. Specify similarly EnglishProductName for Product key, EnglishProductCategoryName for product category key and EnglishProductSubcategoryName for product subcategory key in Products dimension.

11. Let us give query for a specific product category Bikes as follows

SELECT [Product].[Product Category Key].[Bikes]
ON COLUMNS
FROM DemoCube
OR
SELECT
[Product].[Product Category Key].&[1]
ON COLUMNS
FROM DemoCube

12. Let us add rows now (add another axis)

SELECT [Product].[Product Category Key].&[1]
ON COLUMNS,
Customer].[Customer Key].MEMBERS ON ROWS
FROM
DemoCube

With this we get Sales Amount for Bikes for all different customers

This can also be achieved by using ordinals as 0 and 1 instead or COLUMNS and ROWS

13.

SELECT NON EMPTY [Product].[Product Category Key].MEMBERS
ON COLUMNS,
[Customer].[Customer Key].MEMBERS ON ROWS
FROM
DemoCube

to get all categories (we added NON EMPTY to get rid of null values)
The result is as follows:

clip_image006


14. Try following query to see Order Quantity for various categories

SELECT [Measures].[Order Quantity]
ON COLUMNS,
[Product].[Product Category Key].MEMBERS ON ROWS
FROM
DemoCube

15. Let us see how to add a calculated member

WITH MEMBER Measures.[Calculated Member] AS
([Measures].[Order Quantity] * [Measures].[Unit Price])
SELECT NON EMPTY {Measures.[Calculated Member],
[Measures].[Sales Amount]} ON COLUMNS,
NON EMPTY [Product].[Product Category Key].MEMBERS on ROWS
FROM
DemoCube

First we calculate the member and use it with select to view the result

clip_image008

16. If we replace Members after Produt Category Key with CHILDREN we get the result as follows

SELECT NON EMPTY {Measures.[Calculated Member],
[Measures].[Sales Amount]} ON COLUMNS,
NON EMPTY [Product].[Product Category Key].CHILDREN on ROWS
FROM
DemoCube

clip_image010

We get only the (non empty) children for categories, all categories are not displayed.

17. Let us see how to display results in order

For this we will first create of products as follows : Within category, Product sub category and within it product name.

Select Product Dimension, drag and drop Product Category key on hierarchies, drag sub category within it and product key within it, name this hierarchy as Product-Category. Deploy the changes to analysis server.

Let us give query without order

select NON EMPTY
{[Measures].[Order Quantity],[Measures].[Sales Amount]} ON 0,
NON EMPTY DESCENDANTS
([Product].[Product-Category].[Product Subcategory Key].[gloves],
,after)
on 1 from democube

The result looks as follows

clip_image012

With descendants function we can use SELF_AND_AFTER clause instead of AFTER clause to get the current descendants member including the specified member
Now let us give query with Order function:

select NON EMPTY
{[Measures].[Order Quantity],[Measures].[Sales Amount]} ON 0,
NON EMPTY ORDER(
DESCENDANTS
([Product].[Product-Category].[Product Subcategory Key].[gloves],
,after),
[Measures].[Sales Amount]
,asc) on 1
from democube

The result will be orderd on Sales Amout as follows

clip_image014


18. Let us add one more sub category and increase a bit of complexity

select NON EMPTY
{[Measures].[Order Quantity],[Measures].[Sales Amount]}
ON 0,
NON EMPTY ORDER(
{DESCENDANTS
([Product].[Product-Category].[Product Subcategory Key].[gloves],
,after),
DESCENDANTS
([Product].[Product-Category].[Product Subcategory Key].[vests],
,after)},
[Measures].[Sales Amount]
,asc) on 1
from democube

In this case we see the result ordered within a particular sub category, sales amount wise.

clip_image016

The result of SELF_AND_AFTER clause is as follows:

clip_image018

In this we see the ‘gloves’ and’ vests’ also included in the result because of the changed clause in descendants function.

In next article we will talk about some advanced functions from MDX.

Custom Assembly in SQL Server Reporting Services (SQL Server 2008)

As we discussed in the last article, sometimes it may be necessary to add functionality which is too complicated for embedded code to handle or there could be some functionality that is to be used in various reports. Since Embedded code can only be used in the report where you have declared, to make the functionality available in multiple reports, you can use custom assembly.

Let us continue with the previous example where depending upon the count, we will specify the font color. We will take the value of count as a parameter and return the font color.

Let us create a class library with following code:

C#

namespace CustomAssembly
{
public class CustomClass
{
public string ReturnColorName(Int16 count)
{
string returnValue = string.Empty;

if (count == 1)
{
returnValue = "Red";
}
else if (count <= 10)
{
returnValue = "Yellow";
}
else
{
returnValue = "Green";
}

return returnValue;
}
}
}

VB.NET

Namespace CustomAssembly
Public Class CustomClass
Public Function ReturnColorName(ByVal count As Int16) As String
Dim
returnValue As String = String.Empty

If count = 1 Then
returnValue = "Red"
ElseIf count <= 10 Then
returnValue = "Yellow"
Else
returnValue = "Green"
End If

Return
returnValue
End Function
End Class
End Namespace

Build the assembly. Go to Report, Report Properties and Select References tab

clip_image002

We need not give the instance name if we are working with static method. In this case we are working with an instance method.

Now we need to copy the assembly created in the folder :

<drive name>\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies

when we are working with the designer.

To make it available for deployed reports, we would need to copy it in the following folder:

<drive name>\Program Files\Microsoft SQL Server\MSRS10.SQL08\Reporting Services\ReportServer\bin

Now specify following expression for font color

=Code.MyClass.ReturnColorName(Fields!<count field name>.Value)
And you are good to go!

Using Embedded Code in SQL Server Reporting services (SQL Server 2008)

Sometimes we may require using the same expression at many places in a report. Off course se can use the same expression at every place. But imagine the pain if we need to change the expression? In such situations it will be a good practice to use embedded code.

In this article we will see a step by step implementation of Embedded Code

In the report I am using a count field and will change the font color depending upon the value for the field

In your project, Go to Report, Report Properties and select Code tab

clip_image002

The count is 1: font color is red

The count is from 2 till 10: font color is yellow

The count more than 10: font color is green

Add following code to Custom Code

Function ReturnColor(ByVal count As Integer) As String
Dim returnValue As String
Select Case count
Case Is
=1
returnValue = "Red"
Case Is < 10
returnValue = "Yellow"
Case Is > 10
returnValue = "Green"
End Select
Return
returnValue
End Function

In order to access this function in code, we need to enter following in font expression

=Code.ReturnColor(Fields!<Field with count>.Value)

The limitation of using embedded code is it can only be used in the report where you have declared it. In next article we will see how to add custom assembly, which can be used for multiple reports.

Consume a Web Service in SQL Server Integration Services

In this post, we will see how to consume a webservice in SSIS using Web Service Task

Using Web Service Task

Web Service Task is used to execute Web Method. We can get the value returned from the web service, assign it to a variable and later use it in SSIS package. This can also be used to get a list of available values, store it into a file and use that file as a data source for the package.

This task is available as a control flow task; when dragged and dropped onto design area we need to specify following settings

clip_image002

General: We see that there are some straightforward settings like Name and Description for the task. With HttpConnection manager you can refer to URL where the web service is hosted. The connection manager displays the following settings:

clip_image004

We see that along with Server URL you can specify user credentials with the client certificate, time out and chunk size. With HttpConnection you can use anonymous or basic authentication. Windows authentication is not supported.

Example: http://<server name>/<Web service Project><Service name>.asmx?WSDL

We also have a WSDLFile option with which the local copy of WSDL file will be saved.

You have two ways of configuring settings. First one is to download WSDL file manually and save it in some location. Second one is to include the URL with ?WSDL as shown in the example and download WSDL with the command button.

You can select whether to overwrite the file or not.

Input: Once we have specified the options from General tab we can specify the web service method and give parameters if required

clip_image006

If the web method requires any parameters, the list will automatically be supplied to which you can send values as constants or with the help of variables declared in pakage.

Output: with this you option, can send the value returned from the web method to either a variable or save it in a file as shown below

clip_image008

With this we will see a demo of working with Web Service Task

I have used a web service with two web methods, one which takes input parameter as EmployeeID and returns data related to the employee by using tables HumanResources.Employee, HumanResources.EmployeeAddress and Person.Contact from AdventureWorks database and the second which is based on Person.Contact table in AdventureWorks database (which returns all the records from the table)

Following are the two web methods:

[WebMethod]
public string SendDetails(int EmpId)
{
try
{

System.Data.SqlClient.SqlConnection cn = new
System.Data.SqlClient.SqlConnection();
cn.ConnectionString = @"data source=<server name>;" +
"initial catalog=adventureworks;user id=<user name>;password=<password>";
cn.Open();
System.Data.SqlClient.SqlCommand cmd =
new System.Data.SqlClient.SqlCommand("SELECT HumanResources.Employee.EmployeeID,"+
"Person.Contact.FirstName, Person.Contact.LastName, Person.Contact.EmailAddress" +
" FROM HumanResources.Employee INNER JOIN HumanResources.EmployeeAddress " +
"ON HumanResources.Employee.EmployeeID = " +
"HumanResources.EmployeeAddress.EmployeeID INNER JOIN " +
"Person.Contact ON HumanResources.Employee.ContactID = Person.Contact.ContactID" +
" WHERE HumanResources.Employee.EmployeeID = " + EmpId, cn);

System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();
dr.Read();
return dr["FirstName"].ToString() + " " + dr["LastName"].ToString() +
" " + dr["EmailAddress"].ToString();
}
catch (Exception ex)
{
return ex.Message;
}

}

and

[WebMethod]
public string[] ContactInfo()
{
string[] contacts = null;
try
{

System.Data.SqlClient.SqlConnection cn = new
System.Data.SqlClient.SqlConnection();
//multiple active result set is set to true as there are two command objects
//associated witha single connection
//one which returns the result set and one which is used to get count of records
cn.ConnectionString = @"data source=<server name>;initial catalog=adventureworks;" +
"user id=<user name>;password=<password>;MultipleActiveResultSets=true";
cn.Open();
System.Data.SqlClient.SqlCommand cmdCount =
new System.Data.SqlClient.SqlCommand("SELECT COUNT(*) From Person.Contact", cn);
Int16 count = 0;
System.Data.SqlClient.SqlDataReader drcnt = cmdCount.ExecuteReader();
drcnt.Read();
count = Int16.Parse(drcnt[0].ToString());
contacts = new string[count];
System.Data.SqlClient.SqlCommand cmd =
new System.Data.SqlClient.SqlCommand("SELECT FirstName, LastName, EmailAddress " +
" From Person.Contact", cn);
System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();
Int16 i = 0;
while (dr.Read())
{
contacts[i] = dr[0].ToString() + " " + dr[1].ToString() + "," + dr[2].ToString();
i += 1;
}
return contacts;

}
catch (Exception ex)
{
contacts[0] = ex.Message;

return contacts;
}
}

Let us see how to consume these web methods in Web service task:

1. Create a new Integration Services Project and change the default name for the package to ConsumeWebService.dtsx

2. Drag a sequence container on the design area (each sequence container will have a web service task so that we can execute only one task at a time and need not execute whole package)

3. Create a package level variable named WebServiceValue of string type

4. Drag and drop Web Service Task onto the design area

5. Configure the HttpConnection Manager (from General tab), Input tab to specify Web method name as SendDetails specify the input parameter is value (not a variable) and enter value 1. For output tab select variable and specify the user defined variable created in step 3

Alternatively we can create one more variable of integer type and set it as the input parameter to the web method.

6. We can verify the value returned from web service is correct by adding a script task and displaying the value returned. We will have to specify the ReadOnlyVariable for the script task to the variable in which the value is obtained.

We can use VB.NET or C# language for script when working with SQL Server 2008.

MessageBox.Show(Dts.Variables["User::WebServiceValue"].Value.ToString());

7. Execute the sequence container.

8. Add another sequence container and drag and drop web service task in it.

9. Configure the HttpConnection, select another web method ContactInfo this time.

10. In ‘output’ select File Connection and direct the output returned to a newly created XML file.

11. Execute the sequence container; verify that the file gets created with FirstName and last name with a space in between followed by the email address with a comma for all the records in the table.

That’s it and you can know use the WebService!