Sunday 31 July 2011

Using MERGE statement in SQL Server 2008

‘MERGE’ statement is a new feature in SQL Server 2008. It can be used to perform insert, update and delete operation on a destination table simultaneously based on the results of a join with a source table. Well, it sounds like a bit confusing, but let's see an example on how it can help us.

Assume we have following two tables.

  • STUDENT_A
  • STUDENT_B

Both table are identical in structure (Structure does not need to be identical).

STUDENT_A

img_scr_001

 

STUDENT_B

img_scr_002

 

And we have to update the ‘STUDENT_A’ with the details at ‘STUDENT_B’. We need to compare and if student ID’s are matched, ‘A’ table should be updated with the ‘B’ table. And if the ID’s in ‘B’ Table are new then we have to insert those to the ‘A’ table.

img_scr_003

 

So using the ‘MERGE’ statement we can achieve this in one execution.

Syntax:

MERGE  <Target> [AS T]
USING <Source> [AS S]
ON <Condition>
[WHEN MATCHED THEN <Execution>]
[WHEN NOT MATCHED BY TARGET <Execution>]
[WHEN NOT MATCHED BY SOURCE <Execution>]


And to do the above operation use the following code:


MERGE STUDENT_A AS T
USING STUDENT_B AS S
ON T.ID = S.ID
WHEN MATCHED THEN UPDATE SET T.AGE = S.AGE
WHEN NOT MATCHED THEN INSERT (ID, FNAME, LNAME, AGE) VALUES(S.ID,S.FNAME,S.LNAME,S.AGE);



**Please note that semicolon ‘;’ is mandatory.


So after executing the above code, and if you inspect the Table ‘A’, you can see that it’s updated the way we wanted.


img_scr_005



 


And also you can use additional rules other than your condition. To illustrate that, first we insert a record to both the tables.


insert into STUDENT_A 
select 10, 'John','Doe',30

insert into STUDENT_B
select 10, 'John','Doe',30



And using the following code you can remove the record with matches the condition and have the value 10.


MERGE STUDENT_A AS T
USING STUDENT_B AS S
ON T.ID = S.ID
WHEN MATCHED and S.ID < 5 THEN UPDATE SET T.AGE = S.AGE
WHEN MATCHED and S.ID = 10 THEN DELETE
WHEN NOT MATCHED BY TARGET THEN INSERT (ID, FNAME, LNAME, AGE) VALUES(S.ID,S.FNAME,S.LNAME,S.AGE);



And if you inspect the table A, you can see that it has the same following results:


img_scr_005

Thursday 28 July 2011

How to Use Update Cursors in SQL Server

There can be a situation where you have to use a cursor, even though the experts say not to use cursors or to avoid them as much as possible. But if you look closely, most of the time we use cursors to iterate through a row collection and update the same table.

In these type of situations it is ideal to use a Update Cursor, than using the default read only one.

Consider the following table :

CREATE TABLE [dbo].[SAMPLE_EMPLOYEE](
[EMP_ID] [int] NOT NULL,
[RANDOM_GEN_NO] [VARCHAR](50) NULL
) ON [PRIMARY]


Insert few records to the above table using the following script :


SET NOCOUNT ON
DECLARE @REC_ID AS INT

SET @REC_ID = 1

WHILE (@REC_ID <= 1000)
BEGIN
INSERT INTO SAMPLE_EMPLOYEE
SELECT @REC_ID,NULL

IF(@REC_ID <= 1000)
BEGIN
SET @REC_ID = @REC_ID + 1
CONTINUE
END

ELSE
BEGIN
BREAK
END
END
SET NOCOUNT OFF


Next we will add a Primary Key using the below script (Or you can use the table designer) :


ALTER TABLE [dbo].[SAMPLE_EMPLOYEE] ADD  CONSTRAINT [PK_SAMPLE_EMPLOYEE] PRIMARY KEY CLUSTERED 
(
[EMP_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]


** Please note: A primary key should be there if we are to use an update cursor. Otherwise the cursor will be read only.


Here is how you use the Update Cursor. I have highlighted the areas which is differ from compared with a normal cursor. You have to mention which column you are going to update (or all columns in your selection will be updatable) and you have to use ‘where current of <cursor>’ in your update statement.


img_scr_001_a


SET NOCOUNT ON
DECLARE
@EMP_ID AS INT,
@RANDOM_GEN_NO AS VARCHAR(50),
@TEMP AS VARCHAR(50)



DECLARE EMP_CURSOR CURSOR FOR
SELECT EMP_ID, RANDOM_GEN_NO FROM SAMPLE_EMPLOYEE FOR UPDATE OF RANDOM_GEN_NO
OPEN EMP_CURSOR
FETCH NEXT FROM EMP_CURSOR
INTO @EMP_ID, @RANDOM_GEN_NO

WHILE (@@FETCH_STATUS = 0)
BEGIN
SELECT @TEMP = FLOOR(RAND()*10000000000000)
UPDATE SAMPLE_EMPLOYEE SET RANDOM_GEN_NO = @TEMP WHERE CURRENT OF EMP_CURSOR

FETCH NEXT FROM EMP_CURSOR
INTO @EMP_ID, @RANDOM_GEN_NO
END

CLOSE EMP_CURSOR
DEALLOCATE EMP_CURSOR

SET NOCOUNT OFF

Tuesday 26 July 2011

Fixed ~ Error installing SQL 2008 Business Intelligence Studio and Related Features

 

 

If you try to install/add feature SQL 2008 Business Intelligence Studio, to a machine with VS2008 having installed to a different location than the default, you will most probably get the following error :

img_screen_01

In order to install BI Studio 2008 properly, please do the following :

Find the folder which contains 'devenv.exe' (I have installed Visual Studio in 'D:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE')

Copy and paste the 'devenv.exe.config' file to the following location:

64-Bit
C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE

32-Bit
C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE

And now you proceed with the installation without any issue.

After installation, copy everything from 'C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE' (where you copied the 'devenv.exe.config') and paste it to the directory where you have VS2008 (In my machine it's  'D:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE')

And if you run Visual Studio 2008 you can see that the Business Intelligence Projects are now available.

img_screen_02_a

Sometimes you will be prompted to locate the 'devenv.exe' when opening the Business Intelligence Development Studio. Please adjust the shortcut or you can use the 'Visual Studio 2008' IDE.

img_screen_03

Thursday 21 July 2011

[Resolved] - AdventureWorks2008 sample database not available after installation

 

Many of you who have tried installing AdventureWorks2008 sample database, might have come across with an issue, which after installing the database package (using the executable), 'AdventureWorks2008' is missing from the database list. This is not a bug in SQL server or any error in the installer.
 
img_screen_04_a
 
In order to get the 'AdventureWorks2008' installed following should be fulfilled:
 
1.          Full-text search should be installed and running
 
img_screen_01_a
 
2.          FILESTREAM should be enabled and running
 
img_screen_03_a
 
Enabling FILESTREAM:

  1. Go to SQL Server Configuration Manager
  2. Click on SQL Server Services (left pane)
  3. Right click on the correct SQL Server Service (if you have more than one instance)
  4. Select properties from the menu
  5. Go to FILESTREAM tab and check the ‘Enable FILESTREAM for Transact-SQL access’ check box.
  6. Apply changes.

And if you still don’t see it in your database list, please reinstall the package.

img_screen_05_a

Thursday 14 July 2011

Extension Methods in C#

                                            
As name implies extension methods allow existing classes to be extended without using inheritance or changing class’s source code.

Some important points when using extension methods:

•    You cannot use extension methods to override existing methods
•    An extension method with the same name and signature as an instance method must not be called
•    The concept must not be applied to fields, properties or events
•    Do not overuse

As an example, we’ll create an extension method to existing ‘String’ class. We’ll implement the functionality of converting a string to a proper case. (Any given string will be converted to lower case, having the first letter of each word in upper case. E.g.: ‘this is sample text’ will be converted to ‘This Is Sample Text’)

Add a class and add the following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace ExtensionMethods {
public static class SampleExtensionMethods {
public static string ToProper(this string zSource) {
StringBuilder sb = new StringBuilder();

string zTemp = zSource.ToLower();
List<string> data = zTemp.Split(new char[] { ' ' }).ToList<string>();
if (data.Count > 0) {
foreach (string element in data) {
if (element.Trim().Length > 0) {
sb.Append(element.Trim().Substring(0, 1).ToUpper() + element.Trim().Substring(1, element.Trim().Length - 1) + " ");
}
}
}

return sb.ToString().Trim();
}
}
}



please note that the class that the class should be static and the method should be public (Unless you are writing it within the same calss which you intend to use it). And also in input the parameter I have mentioned 'this'. This will tell the compiler to add the following method to the 'String' class.


Before using include the namspace. (I have used 'ExtensionMethods' as the namespace)


using ExtensionMethods;


And you can use the method we created using this syntax :


SomeStringVar.ToProper()


E.g:


using System;
using System.Text;
using ExtensionMethods;

namespace SampleConsoleApplicationA {
class SampleExtMethod {
static void Main(string[] args) {
string zSample = "this is sample text";
Console.WriteLine("Input : " + zSample);
Console.WriteLine("Output : " + zSample.ToProper());
Console.ReadLine();


}
}
}



And if you run the application you can get the below output (I have used a console application to illustrate this)


Extension Method

Delegates in C#

                                            
What's a delegate

A delegate is a type that safely wraps/encapsulate a  method. It is similar to 'function pointers' in C/C++, but it's type safe.

 

When to use a delegate

Use a delegate when :

  • An eventing design pattern is used.
  • It is desirable to encapsulate a static method.
  • The caller has no need access other properties, methods, or interfaces on the object implementing the method.
  • Easy composition is desired.
  • A class may need more than one implementation of the method.

There was a good example given on a book that I recently referenced.
'Consider your will—your last will and testament. It’s a set of instructions—“pay the bills, make a donation to charity, leave the rest of my estate to the cat,” for instance. You write it before your death, and leave it in an appropriately safe place. After your death, your attorney will (you hope!) act on those instructions.'

In order to a delegate to proceed, following four things need to happen:
* The delegate type needs to be declared.
* There must be a method containing the code to execute.
* A delegate instance must be created.
* The delegate instance must be invoked.

Declaring delegate type
Declaration of a delegate type specifies what kind of action can be represented by instances of the type.

E.g :

delegate void MySampleDelegate(string zParameter)



If we are creating an instance of the above delegate, we should have a method with one string parameter and void return type.



Method containing the code to execute
There should be a method which matches the signature of the delegate. Method can be either static or non static. I will take two examples to illustrate a static method and a non static method. I will use the following two methods in the 'DelegateClass' class.


E.g :


public class DelegateClass {
public static void MySampleDelegateMethodStatic(string zParameter) {
Console.WriteLine("From static method. Parameter : {0}", zParameter);
}

void MySampleDelegateMethodNonStatic(string zParameter) {
Console.WriteLine("From non static method. Parameter : {0}", zParameter);
}
}



Creating a delegate instance
When creating delegate instances static methods can  be passed directly. But for non static methods an instance should be created and passed that to the delegate.


E.g :    [Static Method]


MySampleDelegate delMethodA = new MySampleDelegate(DelegateClass.MySampleDelegateMethodStatic);


E.g :    [Non Static Method]


DelegateClass deligateClass = new DelegateClass();
MySampleDelegate delMethodB = new MySampleDelegate(deligateClass.MySampleDelegateMethodNonStatic);


Or


MySampleDelegate delMethodB = new MySampleDelegate(new DelegateClass().MySampleDelegateMethodNonStatic);


Invoking delegate method
It's a matter of calling the Invoke method on the delegate instance.


E.g :


delMethodA.Invoke("Parameter A");
delMethodB.Invoke("Parameter B");



Here is the complete source code for the above example. I have used a console application to illustrate this :


using System;
using System.Text;


namespace SampleConsoleApplicationA {

delegate void MySampleDelegate(string zParameter);

class Program {
static void Main(string[] args) {

MySampleDelegate delMethodA = new MySampleDelegate(DelegateClass.MySampleDelegateMethodStatic);
MySampleDelegate delMethodB = new MySampleDelegate(new DelegateClass().MySampleDelegateMethodNonStatic);

delMethodA.Invoke("Parameter A");
delMethodB.Invoke("Parameter B");

Console.ReadLine();
}
}

public class DelegateClass {
public static void MySampleDelegateMethodStatic(string zParameter) {
Console.WriteLine("From static method. Parameter : {0}", zParameter);
}

public void MySampleDelegateMethodNonStatic(string zParameter) {
Console.WriteLine("From non static method. Parameter : {0}", zParameter);
}
}
}






And when you run your application you will get the following output:


Delegate Sample


Instead of using separate delegate instances, you can combine and execute delegates. We have to use the 'Combine' method in Delegate class. To illustrate this I will alter my 'DelegateClass' as shown below :


public class DelegateClass {

public void MySampleMethodA(string zParameter) {
Console.WriteLine("MySampleMethodA. Parameter : {0}", zParameter);
}

public void MySampleMethodB(string zParameter) {
Console.WriteLine("MySampleMethodB. Parameter : {0}", zParameter);
}

public void MySampleMethodC(string zParameter) {
Console.WriteLine("MySampleMethodC. Parameter : {0}", zParameter);
}

}



To create instances and invoke :



MySampleDelegate[] mySampleDelegates = new MySampleDelegate[]{
new MySampleDelegate(new DelegateClass().MySampleMethodA),
new MySampleDelegate(new DelegateClass().MySampleMethodB),
new MySampleDelegate(new DelegateClass().MySampleMethodC)
};

MySampleDelegate sample = (MySampleDelegate)Delegate.Combine(mySampleDelegates);
sample.Invoke("Parameter X");



Or

MySampleDelegate D, deligateA, deligateB, deligateC;

deligateA = new DelegateClass().MySampleMethodA;
deligateB = new DelegateClass().MySampleMethodB;
deligateC = new DelegateClass().MySampleMethodC;

D = deligateA + deligateB + deligateC;

D("Parameter X");



 


The complete source code :


using System;
using System.Text;


namespace SampleConsoleApplicationA {

delegate void MySampleDelegate(string zParameter);

class Program {
static void Main(string[] args) {

MySampleDelegate[] mySampleDelegates = new MySampleDelegate[]{
new MySampleDelegate(new DelegateClass().MySampleMethodA),
new MySampleDelegate(new DelegateClass().MySampleMethodB),
new MySampleDelegate(new DelegateClass().MySampleMethodC)
};

MySampleDelegate sample = (MySampleDelegate)Delegate.Combine(mySampleDelegates);
sample.Invoke("Parameter X");


/*
MySampleDelegate D, deligateA, deligateB, deligateC;

deligateA = new DelegateClass().MySampleMethodA;
deligateB = new DelegateClass().MySampleMethodB;
deligateC = new DelegateClass().MySampleMethodC;

D = deligateA + deligateB + deligateC;

D("Parameter X");

*/

Console.ReadLine();
}
}

public class DelegateClass {

public void MySampleMethodA(string zParameter) {
Console.WriteLine("MySampleMethodA. Parameter : {0}", zParameter);
}

public void MySampleMethodB(string zParameter) {
Console.WriteLine("MySampleMethodB. Parameter : {0}", zParameter);
}

public void MySampleMethodC(string zParameter) {
Console.WriteLine("MySampleMethodC. Parameter : {0}", zParameter);
}

}
}



 


An when you run the application, you will get the following output:


Delegate Sample B