Ashwani's profileAshwani Roy's BI BlogPhotosBlogListsMore Tools Help

Ashwani Roy

Occupation
Location
Interests

SQL BITS 5

Submit a session for SQLBits IV

MVP-SQL Server

Microsoft MVP Blog

Ashwani Roy's BI Blog

My experince with SQL Server/Visual Studio and Business Intelligence
January 17

Very Basic Generics , LINQ and Solution to Eric Lippert’s Problem

It was lunch time was I was thinking of stepping out for a good lunch at Nando’s when a friend of mine sent me an email and he was taking about some issue he has come up with where in he has to order something . I said use generics . Well then I came across this puzzle on Eric’s blog (he is a Senior Dev in C# compiler team). The problem is mentioned here http://blogs.msdn.com/ericlippert/archive/2009/04/15/comma-quibbling.aspx

I decided to solve it and some how used generics , LINQ , Lambda expression and I thought my this blog can serve as a small pointer on how to use it in day to day programming. (For details on these please go to MSDN or somewhere else. This entry is just a demo of what these stuff look like and how can it be used in very simple terms)

So now the PROBLEM

Given a sequence of strings, concatenate them in a way similar to natural language.  For example the sequence "ABC", "DEF", "G", and "H" should be output as: {ABC, DEF, G and H}  "ABC" and "DEF" should be output as...   {ABC and DEF} and finally an empty sequence should yield the following output: {} . Now I am not going to handle the last bit that is the empty string part so just leave it.

So Here is the code (it is a console app and should work from VS 2008 onwards)

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections;
  4. using System.Text;
  5. using System.Linq;
  6.  
  7. namespace intrestingCSharpe
  8. {
  9.  
  10.     public class mySortedList
  11.     {
  12.         private string _str;
  13.  
  14.         public string Str
  15.         {
  16.             get { return _str; }
  17.             set { _str = value; }
  18.         }
  19.         private int _pos;
  20.  
  21.         public int Pos
  22.         {
  23.             get { return _pos; }
  24.             set { _pos = value; }
  25.         }
  26.  
  27.  
  28.  
  29.  
  30.  
  31.     }
  32.     public class Program
  33.     {
  34.         public static int retAsciOfFirst(char ch)
  35.         {
  36.             return Convert.ToInt32(ch);
  37.         }
  38.  
  39.         static void Main(string[] args)
  40.         {
  41.  
  42.            List<string> sort = new List<string>();
  43.            sort.Add("ABC");
  44.            sort.Add("G");
  45.            sort.Add("DEF");
  46.            sort.Add("H");
  47.  
  48.  
  49.            List<mySortedList> sortedlist = new List<mySortedList>();
  50.  
  51.  
  52.            foreach (string s in sort)
  53.            {
  54.                mySortedList sorted = new mySortedList();
  55.                sorted.Str = s;
  56.                sorted.Pos = Convert.ToInt32(s.ToCharArray().GetValue(0));
  57.                sortedlist.Add(sorted);
  58.            }
  59.            IEnumerable<string> sortDescendingQuery =
  60.            from s in sortedlist
  61.            orderby s.Pos
  62.            select s.Str ;
  63.  
  64.            string contcatenator; int count = sortDescendingQuery.Count(); int counter = 1;
  65.  
  66.            foreach (string  s in sortDescendingQuery)
  67.            {
  68.  
  69.                if(counter == 1)
  70.                {
  71.                    contcatenator = "";
  72.                    Console.Write("{0}", "{"+contcatenator + s);
  73.                }
  74.                else if (counter > 1 && counter < count)
  75.                {
  76.                    contcatenator = ",";
  77.                    Console.Write("{0}", contcatenator + s);
  78.                }
  79.                else if (counter ==  count)
  80.                {
  81.                    contcatenator = " AND ";
  82.                    Console.Write("{0}", contcatenator + s+"}");
  83.                }
  84.  
  85.  
  86.  
  87.                counter++;
  88.  
  89.            }
  90.  
  91.             Console.Read();
  92.  
  93.         }
  94.     }
  95.  
  96. }

So some explanation now. I created a class(type) mySortedList which has 2 properties str and pos and I am using this class as the generic type. Generic list<T> needs a type so I can use my class. Handy here as I can store a list of my class type and enumerate over the collection and so on.

Now I have written a small LINQ query as well to do the ordering. It does the job. but a even better way will be to use the lambda expression to order this List<mySorterList>().

IMPROVEMET 1 : I will use a delegate to the ordering and not created another list but rather order the same list

So Here is the code . Just Comment the LINQ query and replace it with the delegate code till the end

Code Snippet
  1. sortedlist.Sort(delegate(mySortedList s1, mySortedList s2) { return s1.Pos.CompareTo(s2.Pos); });
  2.  
  3. string contcatenator; int count = sortedlist.Count(); int counter = 1;
  4.  
  5. foreach (mySortedList s in sortedlist)
  6. {
  7.  
  8.     if(counter == 1)
  9.     {
  10.         contcatenator = "";
  11.         Console.Write("{0}", "{"+contcatenator + s.Str);
  12.     }
  13.     else if (counter > 1 && counter < count)
  14.     {
  15.         contcatenator = ",";
  16.         Console.Write("{0}", contcatenator + s.Str);
  17.     }
  18.     else if (counter ==  count)
  19.     {
  20.         contcatenator = " AND ";
  21.         Console.Write("{0}", contcatenator + s.Str + "}");
  22.     }
  23.  
  24.  
  25.  
  26.     counter++;
  27.  
  28. }
  29.  
  30.  Console.Read();

 

Nice. But as I can use delegate here why not use LAMBDA Expression instead.

Just a small syntax explanation . Lambda expression are a functional programming construct and has been added to C# 3.0. The way it is written is

Sqr X => X*X meaning a function Sqr is a function of X which “goes to” X*X

ok so lets replace the above ordering by using lambda expression. The code becomes

I can replace the delegate by this

Code Snippet
  1. sortedlist.Sort((mySortedList p1, mySortedList p2) => p1.Pos.CompareTo(p2.Pos));

 

There are many other ways . I can use anonymous method to this sort return etc etc. So IN sort C#3.0 ‘s functional programming features like generics , LINQ , Lambda expressions , anonymous method are amazing . So do pay some attention to them to clean up your code written in frameworks 1.0 and 1.1 (2.0 has generics and anonymous method).

happy coding. and ya the output is (many other have used other way but I used ASCII encoding to have some more fun)

image

December 19

Writing Test Cases for Database Queries and Stored Procedure using VS 2010

I was playing around with a recently downloaded Beta 2 of VS 2010. As of me , I work a lot with Databases and Data warehouses but I did have an opportunity to work with C# based development using ADO.NET entity framework sometime back.

I am a big fan or writing test cases and making sure that I achieve a good code coverage. With VS 2010 I can write test cases for database objects like stored procedures. In this blog post I am going to write a very small bit about how you can write test cases for SQL Queries using VS 2010. (You don’t need any NUnit or csUnit as you might need in previous versions of VS and even in that case I don’t see an easy way as VS 2010 provides).

Start VS 2010 and go to ribbon on the top

image

Click New Test and select Database Unit Test

image

Configure the database connection string and Project name and other stuff

image

 

You will have a window which will look like this. Click on the CREATE NEW link

image

 

You can my TestMyProc.cs . This is a C# class. You can Paste you SQL code in the designer and the C# class will wrap this and execute it using ADO.NET . You need not worry writing the TESTFIXTURES and etc etc

The designer has this commented bit on top which is self explanatory.

/*
Add T-SQL statements here to exercise the database object
that you want to test.

To test a stored procedure, invoke it here by adding
an EXEC statement that has appropriate parameters.

In the lower pane, you can add test conditions that verify
whether the results of your T-SQL statements match what
you expect.
*/

Ok . Now lest write some test . Lets Begin with a negative on. Which Will fail.

I have configured my Database to connect to adventureworks.

The SQL Code I want to test is

SELECT * FROM HumanResources.Employee   WHERE BusinessEntityID  = 1 --will fail

Now go down to test condition panel. Here you can specify the conditions which will be based on what is the expected output. So Lets say I don’t expect any result set.

image

After you have configured the Condition you need to run this test.

image

The test result panel will have the below output stating that test has failed.

image

Now change the SQL Query to

SELECT * FROM HumanResources.Employee   WHERE BusinessEntityID  = -1 --will succeed

and run the test again. The test result panel will show PASSED

image

So we have written our first Unit Test to Test a SQL Query. The same thing can be extended to Stored Procedures. I don’t know as of now if it supports MDX unit testing out of the box but if go the code behind (F7) you will see a C# class. You can add ADOMD or AMO and test MDX , XMLA or anything else in theory. I have not tried it yet though.

Happy Test Driven Development for Database Guys!!. I will be blogging more on this.

December 09

Using AMO to query cube , partitions and other SSAS objects- How to find query definition of the partition

I was doing some work around AMO and SSAS and I need to load a partition from database and read some of its properties . I was able to do most of them but the <QueryDefinition> was a bit of issue. I thought I will write a small blog on it. It might be useful for someone.

But if this Partition uses a dsvTable binding than this wont work. Anyway this is a small console application that does that plus it also serves a intro to how to use AMO to connect to Analysis service Server and use the Object model to program against the SSAS Objects.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.AnalysisServices;
using System.IO;

namespace TestBed
{
    class Program
    {
        static void Main(string[] args)
        {
            Server srv = new Server();
            srv.Connect("Data source=IMGLT119;Initial catalog=Adventure Works DW");
            Database db = srv.Databases.FindByName("Adventure Works DW");
            Console.WriteLine("Connected to Database {0} on server {1}", db.Name, srv.Name);
            foreach (Cube cb in db.Cubes)
            {
                if (cb.Name == "Adventure Works")
                {
                    foreach (MeasureGroup mg in cb.MeasureGroups)
                    {
                        foreach (Partition pt in mg.Partitions)
                        {
                            
                                //You can access the partition properties . Well Most of it.
                                Console.Write(" partition name is {0} partition slice before is {1}", pt.Name, pt.Slice);
                                QueryBinding qb = new QueryBinding();
                                //I had a bit of glitch with finding the Query Definition . If you have table binding than this wont work . 
                                qb = (QueryBinding)pt.Source;
                                Console.WriteLine("Query Definition {0}", qb.QueryDefinition.ToString()  );
                                break;
                            }

                        }
                    }

                    break;
            }
            Console.Read();
        }
    }
}
   

Transaction Log Explosion

A few days back I had one of my SQL Dev friend asked me a question. “I fired a DML on one of my tables and a strange thing (to me) is that it generated ~180GB of transaction logs!!! . I did not expect it to grow so much so what happened.”

Well I though I would blog about what I told him , which might be useful to some.

Transaction Log explosion is a common occurrence when there is such a mammoth size DML operation issued against a large table of this size and the DML are not atomic transactions.

T-Log growth is a factor or size or rows, size of indexes, atomicity of transactions, if there is any trigger on the table, database recovery model and a few more.

There is one more thing. If the T-Log is set to expand in % it is not good. Here is an example.

Let’s say our initial size is 100 MB with 10%. The growth will be a non-linear pattern causing a sudden expansion like

100

110

121

133.1

146.41

161.051

177.1561

194.8717

214.3589

235.7948

259.3742

If we plot it will soon become a exponential series

clip_image002

How to avoid this explosion to happen

You need to delete data in sized batches that will commit upon completion, thus keeping the log file to a reasonable size.

1. One easy way to achieve this is using TOP with DELETE statement  -- I would do this

2. Or SET ROWCOUNT

DECLARE @i INT

SET @i = 1

SET ROWCOUNT 10000

WHILE @i <> 0

BEGIN

    DELETE FROM HumanResources.Employee    WHERE Employee.HireDate < '01-01-1900'

    SELECT @i = @@ROWCOUNT

END

SET ROWCOUNT 0

3. Set the size of the transaction log files to a large value to avoid the automatic expansion of the transaction log files.

4. Configure the automatic expansion of transaction log files by using memory units instead of a percentage after you thoroughly evaluate the optimum memory size.

More here http://support.microsoft.com/kb/873235

October 26

F#- What , Why and BI – My First Look

I am preparing a demo for User Group in UK of how F# can used with Business Intelligence. Frankly speaking I don’t know the end result but as I go along I am going to keep blogging about what I am learning in F# with simple examples. The aim is to have a series of blog post on this new language (something like I have done for ADO.NET entity Framework on http://csentities.wordpress.com ) which will serve as a quick start guide and possibly will open up areas of discussion where I will be using F# with BI to add the power of functional programming into Business Intelligence.

I will be using VS 2010 (I have a Beta 2 Ultimate as of now but the code should work with VS 2008 and fsi.exe).

So Lets go ahead and start a new Blank Solution

image

Now lets go ahead and add a new F# console application.

image

Now Open the program.fs and paste the code given below in it.

open System
let a = 2
Console.WriteLine(a)
Console.Read()

 

Now if you hover over the Console.Read() you will see an error saying “The expression should have type ‘uint’, but has type ‘int’. Use ‘ignore’ to discard the result of the expression , or let to bind to a name.”

image

If you write Console.Read() in C# you will not get any diagnostic warning like this. This reminds you that you want to either pipe the result to ignore (e.g. if just calling a function for its side-effects) or else use the result.  There are a handful of minor diagnostic improvements like this (though there is still plenty of room for us to continue to improve).

If you want to get rid of this warning message then use the code below.

open System
let a = 2
Console.WriteLine(a)
ignore(Console.Read())

 

Run the application and your output will be look like this

image

Console.Read is just to hold the screen for us to see it and the screen exits when you hit any key after this.

So by now we know how to create a simple F# console application writes something to the console. Watch out for the coming posts.

October 02

Microsoft MVP Award to Me !! Thank you all

I got a email today at 4:00 PM from Microsoft MVP award which read

Dear Ashwani Roy,
Congratulations! We are pleased to present you with the 2009 Microsoft® MVP Award! This award is given to exceptional technical community leaders who actively share their high quality, real world expertise with others. We appreciate your outstanding contributions in SQL Server technical communities during the past year

I would like to thank UK SQL Server Community , my blog readers my peers and friends and I hope I will keep adding value to community.

How can solve order effect your MDX calculations

[Old post reposted as I was not very happy with the formatting]

Have a look at this query

   1:  WITH
   2:  MEMBER [Measures].[REFUNDS] AS [Measures].[Internet Sales Amount] – [Measures].[Internet Sales Amount] * .4
   3:  MEMBER [Measures].[PROFIT] AS [Measures].[Internet Sales Amount] – [Measures].[REFUNDS]
   4:  MEMBER [Product].[Product].[Top10] AS
   5:  sum(
   6:  TOPCOUNT([Product].[Product].[Product].MEMBERS
   7:  , 10
   8:  , [Measures].[Internet Sales Amount]
   9:  )
  10:  ,
  11:  ([Measures].CurrentMember)
  12:  )
  13:  MEMBER [Product].[Product].[Top10PercOfTotal] AS [Product].[Product].[Top10]/[Product].[Product].[All Products]
  14:  SELECT 
  15:  {
  16:  [Measures].[Internet Sales Amount],
  17:  [Measures].[REFUNDS],
  18:  [Measures].[PROFIT]
  19:  } ON COLUMNS,
  20:  {
  21:  [Product].[Product].[Top10]
  22:  ,[Product].[Product].[Top10PercOfTotal]
  23:  ,[Product].[Product].[All Products]
  24:  } 
  25:  ON ROWS
  26:  FROM [Adventure Works]

 

This yields same result as yours i.e. not a flat cell by cell division

  Internet Sales Amount REFUNDS PROFIT
Top10 $10,355,525.92 $6,213,315.55 $4,142,210.37
Top10PercOfTotal 0.35272454 0.211634724 0.141089816
All Products $29,358,677.22 $17,615,206.33 $11,743,470.89

 

I don’t expect it to produce this result . If the computations was going as planned the output should be 0.35272454  (35 %) for each.

I have altered the SOLVE ORDER (this is the property which determines the order of cell computation) .

Here is modified query

   1:  WITH
   2:  MEMBER [Measures].[REFUNDS] AS [Measures].[Internet Sales Amount] - [Measures].[Internet Sales Amount] * .4,SOLVE_ORDER = 1
   3:  MEMBER [Measures].[PROFIT] AS   [Measures].[Internet Sales Amount] - [Measures].[REFUNDS],SOLVE_ORDER = 2
   4:   
   5:  MEMBER [Product].[Product].[Top10] AS
   6:   sum(
   7:    TOPCOUNT([Product].[Product].[Product].MEMBERS
   8:    , 10
   9:    , [Measures].[Internet Sales Amount]
  10:    )
  11:    ,
  12:    ([Measures].CurrentMember)
  13:    )
  14:  ,SOLVE_ORDER = 3
  15:   
  16:  MEMBER [Product].[Product].[Top10PercOfTotal] AS 
  17:  [Product].[Product].[Top10]/[Product].[Product].[All Products]
  18:  , FORMAT_STRING = "Percent"
  19:   , SOLVE_ORDER = 4
  20:   
  21:   
  22:   
  23:  SELECT 
  24:   {
  25:    [Measures].[Internet Sales Amount],
  26:    [Measures].[REFUNDS],
  27:    [Measures].[PROFIT]
  28:    } ON COLUMNS,
  29:   {
  30:  [Product].[Product].[Top10]
  31:  ,[Product].[Product].[Top10PercOfTotal]
  32:  ,[Product].[Product].[All Products]
  33:   
  34:    } 
  35:    ON ROWS
  36:  FROM [Adventure Works]
  37:  

 

Here is the output

  Internet Sales Amount REFUNDS PROFIT
Top10 $10,355,525.92 6213315.552 4142210.368
Top10PercOfTotal 35.27% 35.27% 35.27%
All Products $29,358,677.22 $17,615,206.33 $11,743,470.89

 

There you go. SOLVE_ORDER determines the series of how cell computation  will be formed. One with smallest SOLVE_ORDER will be evaluated first.

Hope this explains SOLVE_ORDER and how it works. For more have a look at MDSN @ http://msdn.microsoft.com/en-us/library/ms145539.aspx

September 26

10th SEP – PASS Meeting- What's new in SQL Server 2008 for BI

SSAS 2008 has improved Dimension and Aggregation Designer, new Attribute Relationship Designer, Optimize performance with block computations mode and dynamic management views for enhanced resource monitoring.SSRS 2008 reports has the unique data format of Tablix which allows writing reports with combined advantage of Table and Matrix formats. It can integrate with Microsoft Office SharePoint Server 2007 for central delivery and management of business insight. It also enables users to quickly gain insight into complex sets of data by displaying data graphically with enhanced visualization capabilities. Performance has improved drastically for situations where you are generating large reports.

SSIS Pipeline is optimized to enable more parallel loading of data. You can write script components in C# now. It comes with improved scalability with thread pooling and enhanced lookup transformations. It also performs more functional and scalable data transfers with the improved SQL Server Import and Export Wizard.

Other engine features that you need to be aware of are, improvements to partitioning, change data capture to enable easy extraction of changed data from a production system, backup and table compression which enables better performance and less storage space utilisation. It also comes with optimized Star-Join, improved lock escalation handling, Merge statements and other advanced T SQL enhancements.

 

The slides and demos are available here for download.

August 25

Thursday, 10th September – SQL Server User Group Meeting

The evening's agenda includes the following presentations (see Events section for more details):

What's new in SQL Server 2008 for BI

Presented by Ashwani Roy, MCTS MCITP MCAD MCP

We're also pleased to let you know that SQL Server MVP, Simon Sabin will be presenting. Details about this presentation will be made available shortly.

 

Location:
Bank Of America
5 Canada Square
London E14 5AQ
United Kingdom

 

Register @ http://www.sqlpass.org.uk/