AFTER UPDATE Trigger in sql server

AFTER UPDATE Trigger


To Create AFTER Triggers first of all we need to create a table (but we create two table) for which we apply trigger and need another table that hold all activity in main table.

--We create tblDeparment table below

create table tblDeparment
(
Id int identity(1,1) primary key not null,
DeparmentName varchar(30) not null,
Location Char(8) not null,
DeparmentHead varchar(20) not null
)

--We insert following data's into tblDeparment below

Insert into tblDeparment values('IT','London','Carrie')
Insert into tblDeparment values('HR','Mexico','Toy')
Insert into tblDeparment values('Purchasing','Delhi','Ravi')
Insert into tblDeparment values('Finance','New York','Janie')

--We create tblEmployee table below
create table tblEmployee
(
Id int identity(1,1) primary key not null,
Name varchar(30) not null,
Gender Char(8) not null,
DeparmentId int null constraint FK_tblEmployee_DeparmentId foreign key(DeparmentId) references tblDeparment(Id)    --foreign key
)

--We insert following data's into tblEmployee below

insert into tblEmployee values('Jane', 'Female', 1) 
insert into tblEmployee values('Levis', 'Male', 3)
insert into tblEmployee values('Lee', 'Female', Null)
insert into tblEmployee values('Rose', 'Female', 1)


Here we create two table “tblDeparment” and “tblEmployee “ which are inter-connected through Foreign key constraint.
We will apply trigger for these tables.

Now create table that hold activity of main table by user.
create table tblAudit
(
Id int primary key identity(1,1) not null,
AuditData nvarchar(500)
) 
We have tables are given below with datas.
All tables are selected
Available Tables are selected

Now create the AFTER UPDATE Trigger for “tblEmployee”.
Create trigger trtblEmployeeForUpdate
on tblEmployee                                   
For UPDATE                                        --for Update trigger                                   
As
Begin
    Declare @Id int                                          --Id not change because of primary key
    Select @Id = Id from inserted                            --inserted table use by SQL Server to keep copy of Row which just insert into actual table, the structure of the inserted table is identical to the structure of the actual table
    insert into tblAudit values('An Exiting Employee With Id = ' + cast(@Id as varchar(10)) + 'is Update at' + cast(GETDATE() as nvarchar(20))) --Foreign Key

--CAST is used to convert int type Id to nvarchar that concatenate with "New Employee with Id"
End
Now try to Update data from “tblEmployee” than "trtblEmployeeForDelete" trigger automatically fire and data insert into "tblAudit" and also show in message for two row affected.
delete from tblEmployee where Id=4
Update the table in trigger
After Update trigger update the table
 Now check data from tables.
Tables after update in after update trigger
Select table After update trigger

Example 2

For more understand about AFTER DELETE Trigger we write above Query by different way when more than one update Query execute.
create trigger trtblEmployeeForUpdateByComprision
On tblEmployee
For Update                          --for Update trigger
As
Begin
    Declare @Id int                 --Declare variable Id Not Change because it is Primary key
    Declare @Old_Name nvarchar(30)
    Declare @Old_Gender nvarchar(8)
    declare @Old_DepartmentId int
    
    Declare @New_Name nvarchar(30)
    Declare @New_Gender nvarchar(8)
    declare @New_DepartmentId int
    
    declare @AuditDetails nvarchar(2000)
    
    Select * into #tblTemptblEmployee from inserted               --select data from inserted table (New data which want to update) and insert into temporary table "#tblTemptblEmployee"
    
    while(Exists (Select Id from #tblTemptblEmployee))            --check condition, Id is available or not for which we want to update
    Begin
        Set @AuditDetails = ''
        
        Select Top 1 @Id = Id,                          -- if there are many row in temporary table for updatation, than select top 1 row by id and put into @Id variable
               @New_Name =Name, @New_Gender = Gender,   --since inserted table contain new data, so take data from trigger inserted table(which are transfer into temporary table) and put int @New_Name variable, similarly all
               @New_DepartmentId = DeparmentId
        From #tblTemptblEmployee                        -- select from from temporary table new value and assign to variables
        
        Select @Old_Name = Name, @Old_Gender = Gender,
               @Old_DepartmentId = DeparmentId
        From deleted Where Id= @Id                       --select from deleted table
        
        Set @AuditDetails= 'Employee With Id = ' + Cast(@Id as nvarchar(5)) + 'Changed '        --CAST is used to convert int type Id to nvarchar that concatenate with "New Employee with Id"
        
        If(@Old_Name <> @New_Name)                                                              --check old name not equal to new name
        Set @AuditDetails= @AuditDetails + 'Name From' + @Old_Name + 'To ' + @New_Name          
        
        If(@Old_Gender <> @New_Gender)
        set @AuditDetails = @AuditDetails + ' New Gender ' + @Old_Gender + 'To ' + @New_Gender
        
        If(@Old_DepartmentId <> @New_DepartmentId)
        set @AuditDetails = @AuditDetails + ' New DeparmentId ' + Cast(@Old_DepartmentId as nvarchar(5)) + 'To ' + Cast(@New_DepartmentId as nvarchar(5)) 
        
        insert Into tblAudit values(@AuditDetails)
        delete from #tblTemptblEmployee where Id = @Id         --delete the data from temporary table otherwise it become infinite loop
    End
End 

Now try to Update data from “tblEmployee” than "trtblEmployeeForUpdateByComprision" trigger automatically fire and data insert into "tblAudit" and also show in message for no of row affected.
Update tblEmployee set Name='Rosery' where id=2
After updating check data from tables
selected tables after update the trigger
Select tables after update the trigger

Now Update two row simultaneously.
update tblEmployee set Name='Rose Dosan1', Gender='Male' where id =2
update tblEmployee set Name='Rose Dosan4', Gender='Female' where id =4
After updating check data again from tables
Select tables after update trigger
After Update trigger in Sql Server

Now Update By IN
update tblEmployee set DeparmentId=4 where id IN(1,3)
Now check data from tables.
Select table after update
Select Table After update
Example 3

For more understand about AFTER Update Trigger we take another trigger example.
First we create another table that hold all activity of main table done by user.

create table tblAuditDetailsBy
(
  Id int not null Primary key identity(1,1),
  EmpId int Not Null,
  EmpOldName varchar(30) Not Null,
  EmpNewName varchar(30) Not Null,
  EmpOldGender char(8) Not Null,
  EmpNewGender char(8) Not Null,
  EmpOldDeparmentId int Not Null,
  EmpNewDeparmentId int Not Null,
  AuditAction varchar(1000) Not Null,
  ActionTakenBy varchar(50) Not Null,
  AuditTime datetime not null default Getdate(),
  ServerName varchar(100) Not Null,
  ServerInstanceName varchar(100) Not Null
)

Now create AFTER UPDATE Trigger.
CREATE TRIGGER trtblEmployeeForAfterUpdate
On tblEmployee
AFTER UPDATE                               -- We can use AFTER instead of FOR, in above Query we use FOR
AS
 Begin
 declare @EmpId int;            --Declare variable Id Not Change because it is Primary key
 
 declare @EmpOldName varchar(30);
 declare @EmpOldGender varchar(8);
 declare @EmpOldDepartmentId int;
 
 declare @EmpNewName varchar(30);
 declare @EmpNewGender varchar(8);
 declare @EmpNewDepartmentId int;
 
 declare @EmpAuditAction varchar(1000);
 declare @ActionTakenBy varchar(100);
    declare @ServerName varchar(100);
    declare @ServerInstanceName varchar(100);
    
    set @EmpAuditAction='Update Record ';
 select @EmpId=I.Id from inserted I;         --select value from inserted table(update ) and assign to @EmpId
  
 select @EmpNewName=I.Name,               --select value from inserted table(which we want to update) and assign to @EmpName
        @EmpNewGender=I.Gender,
        @EmpNewDepartmentId=I.DeparmentId from inserted I; 
 
 select @EmpOldName=D.Name,                    --select value from deleted table(old value) and assign to @EmpId
        @EmpOldGender=D.Gender,
        @EmpOldDepartmentId=D.DeparmentId from deleted D;
 
 If(@EmpNewName <> @EmpOldName)    -- We can use also If Update(Name), Name is tblEmployee ColumnName
 Begin  
   set @EmpAuditAction = @EmpAuditAction + ' Name from ' + @EmpOldName + ' to ' + @EmpNewName + ', ' 
 End
 If(@EmpNewGender <> @EmpOldGender)   
 set @EmpAuditAction = @EmpAuditAction + ' Gender from ' + @EmpOldGender + 'to ' + @EmpNewGender + ', '
 If(@EmpNewDepartmentId <> @EmpOldDepartmentId)   
 set @EmpAuditAction = @EmpAuditAction + ' Department Id from ' + CAST(@EmpOldDepartmentId as varchar(5)) + ' to ' + CAST(@EmpNewDepartmentId as varchar(5))
 
 
 set @ActionTakenBy = SYSTEM_USER;
 set @ServerName = CAST( SERVERPROPERTY('ServerName') AS VARCHAR(50));          -- select @@SERVERNAME return server name
 set @ServerInstanceName = CAST( SERVERPROPERTY('MachineName') AS VARCHAR(50));    --SELECT @@servicename return current machine name
 
 insert into tblAuditDetailsBy (EmpId, EmpOldName, EmpNewName, EmpOldGender, EmpNewGender,
                                 EmpOldDeparmentId, EmpNewDeparmentId, AuditAction,
                                ActionTakenBy, AuditTime,ServerName,ServerInstanceName)
                         values(@EmpId,@EmpOldName, @EmpNewName, @EmpOldGender, @EmpNewGender,
                                @EmpOldDepartmentId, @EmpNewDepartmentId, @EmpAuditAction,
                                @ActionTakenBy,GETDATE(), @ServerName, @ServerInstanceName)

 PRINT 'Successfully Fired the AFTER Update Triggers in SQL Server'
End

Now try to update data from "tblEmployee" than "trtblEmployeeForAfterUpdate" trigger automatically fire and data insert into "tblAuditDetailsBy" and also show in message row affected.
update tblEmployee set Name='John', Gender='Male' where id =1
update tblEmployee set Name='Leeky', Gender='Female', DeparmentId=2 where id =2
update the trigger
Update after update trigger
Now Check data from tables.
select table after update table
Select table aftre update trigger fire

AFTER DELETE Trigger in SQL Server with examples


AFTER DELETE Trigger


To Create AFTER Triggers first of all we need to create a table (but we create two table) for which we apply trigger and need another table that hold all activity in main table.
--We Create below tbldepartment Table

create table tblDeparment
(
 Id int identity(1,1) primary key not null,
 DeparmentName varchar(30) not null,
 Location Char(8) not null,
 DeparmentHead varchar(20) not null
)

--We Insert followings datas in tblDepartment

Insert into tblDeparment values('IT','London','Carrie')
Insert into tblDeparment values('HR','Mexico','Toy')
Insert into tblDeparment values('Purchasing','Delhi','Ravi')
Insert into tblDeparment values('Finance','New York','Janie')

--We create another table tblEmployee

create table tblEmployee
(
 Id int identity(1,1) primary key not null,
 Name varchar(30) not null,
 Gender Char(8) not null,
 DeparmentId int null constraint FK_tblEmployee_DeparmentId foreign key(DeparmentId) references tblDeparment(Id)
)

--insert data into table tblEmployee
insert into tblEmployee values('Jane', 'Female', 1) 
insert into tblEmployee values('Levis', 'Male', 3)
insert into tblEmployee values('Lee', 'Female', Null)
insert into tblEmployee values('Rose', 'Female', 1)
Here we create two table “tblDeparment” and “tblEmployee“  which are inter-connected through Foreign key constraint.
Now we will apply trigger for these tables.

Example 1
First of all we need to create table that hold activity in main table by user.

create table tblAudit
(
Id int primary key identity(1,1) not null,
AuditData nvarchar(500)     --keep all activity in his cloumn
) 
Now we have tables are given below with data.

select All tables tblDeparment tblEmployee tblAudit

Now create the AFTER DELETE Trigger for “tblEmployee”.
Create trigger trtblEmployeeForDelete
on tblEmployee
For Delete
As
Begin
    Declare @Id int
    Select @Id = Id from deleted         --Deleted table use by SQL Server to keep copy of Row which just delete from actual table, the structure of the deleted table is identical to the structure of the actual table
    insert into tblAudit values('An Exiting Employee With Id = ' + cast(@Id as varchar(10)) + 'is Deleted at' + cast(GETDATE() as nvarchar(20)))

--CAST is used to convert int type Id to nvarchar that concatenate with "New Employee with Id"
End


Now try to delete data from “tblEmployee” than "trtblEmployeeForDelete" trigger automatically fire and data insert into "tblAudit" and also show in message for affected rows.
delete from tblEmployee where Id=4

Delete row from tblEmployee

Now check data from tables.
Show all tables

Example 2
For more understand about AFTER DELETE Trigger we take another trigger example.
First we create another table that hold all activity of main table done by user.
Create table tblAuditDetailsBy
(
  Id int not null Primary key identity(1,1),
  EmpId int Not Null,
  EmpName varchar(30) Not Null,
  Gender char(8) Not Null,
  DeparmentId int Not Null,
  AuditAction varchar(30) Not Null,
  ActionTakenBy varchar(50) Not Null,
  AuditTime datetime not null default Getdate(),
  ServerName varchar(100) Not Null,
  ServerInstanceName varchar(100) Not Null
)

Now create AFTER DELETE Trigger.
CREATE TRIGGER trtblEmployeeForAfterDelete
On tblEmployee
AFTER DELETE                 -- We can use AFTER instead of FOR, in above Query we use FOR
AS
 Begin
 declare @EmpId int;        --Declare variables
 declare @EmpName varchar(30);
 declare @EmpGender varchar(8);
 declare @EmpDepartmentId int;
 declare @EmpAuditAction varchar(100);
 declare @ActionTakenBy varchar(100)
 declare @ServerName varchar(100);
 declare @ServerInstanceName varchar(100);
    
 select @EmpId=D.Id from deleted D;     --Select Id from deleted and assign to @EmpId. (D is alias name for deleted table)
 select @EmpName=D.Name from deleted D; 
 select @EmpGender=D.Gender from deleted D;
 select @EmpDepartmentId=D.DeparmentId from deleted D; 
 set @EmpAuditAction='Deleted Record ';
 set @ActionTakenBy = SYSTEM_USER;
 set @ServerName = CAST( SERVERPROPERTY('ServerName') AS VARCHAR(50));          -- select @@SERVERNAME, return server name
 set @ServerInstanceName = CAST( SERVERPROPERTY('MachineName') AS VARCHAR(50));    --SELECT @@servicename, return current machine name
 
 insert into tblAuditDetailsBy (EmpId, EmpName, Gender, DeparmentId, AuditAction,
                                ActionTakenBy, AuditTime,ServerName,ServerInstanceName)
                         values(@EmpId,@EmpName,@EmpGender,@EmpDepartmentId,@EmpAuditAction,
                                @ActionTakenBy,GETDATE(), @ServerName, @ServerInstanceName)

 PRINT 'Successfully Fired the AFTER DELETE Triggers in SQL Server'
End

Now try to delete data from "tblEmployee" than "trtblEmployeeForAfterInsert" trigger automatically fire and data insert into "tblAuditDetailsBy" and also show in message for two row affected.
delete from tblEmployee where Id=2


Now Check data's from tables

AFTER INSERT Trigger in SQL Server with examples


AFTER INSERT Trigger

AFTER INSERT Trigger fire after the triggering action Insert but before competition to the databases. AFTER Insert Trigger has the ability that it can rollback modification action or statements.

To Create AFTER INSERT Trigger first of all we need to create a table (but we create two tables) for which we apply Trigger and need another table that hold all activity in main table.

--We create below tblDeparment table

create table tblDeparment
(
 Id int identity(1,1) primary key not null,
 DeparmentName varchar(30) not null,
 Location Char(8) not null,
 DeparmentHead varchar(20) not null
)

--We insert following data into tblDeparment table below

Insert into tblDeparment values('IT','London','Carrie')
Insert into tblDeparment values('HR','Mexico','Toy')
Insert into tblDeparment values('Purchasing','Delhi','Ravi')
Insert into tblDeparment values('Finance','New York','Janie')

--We create another table tblEmployee 

create table tblEmployee
(
 Id int identity(1,1) primary key not null,
 Name varchar(30) not null,
 Gender Char(8) not null,
 DeparmentId int null constraint FK_tblEmployee_DeparmentId foreign key(DeparmentId) references tblDeparment(Id)   --foreign key 
)

--We insert following data into tblEmployee table below

insert into tblEmployee values('Jane', 'Female', 1) 
insert into tblEmployee values('Levis', 'Male', 3)
insert into tblEmployee values('Lee', 'Female', Null)
insert into tblEmployee values('Rose', 'Female', 1)

Here we create two table "tblDeparment" and "tblEmployee" which are inter-connected through Foreign key constraint.
We will apply trigger for these tables.

Inserted and deleted

Before understand trigger we need to understand "inserted" and "deleted" tables which are the special type of the tables use by the trigger and these tables only available in the context of the trigger.

Whenever insert or delete data into or from the table SQL Server manage these tables which retain copy of data which you insert or delete into or from the table.

So when insert or delete data into or from any table SQL Server behind the seen create a table called "inserted" and "deleted" in memory and copy of the row mainted in the inserted and deleted table, and this inserted table can be access inside the context of the trigger.

So structure of "inserted" and "deleted" table identical to the structure or the main table.
If you try to access outside the trigger it will show an error.
--this Trigger only for understand inserted and deleted tables, how usefull for trigger
Create trigger trtblEmployee_ForUnderstand_Inserted_DeletedTable    --"trtblEmployee_ForUnderstand_Inserted_DeletedTable" is a trigger name, tr is use before trigger name for name convention
on tblEmployee                    --create trigger on "tblEmployee"
For update                        --create trigger for update activity
as 
Begin
Select * from inserted            --retain copy of data which you insert into the "tblEmployee".
select * from deleted             --retain copy of data which you delete from the "tblEmployee".          
End


Now create table that hold activity of main table by user.
create table tblAudit
(
Id int primary key identity(1,1) not null,
AuditData nvarchar(500)
) 

We have table are given below with data.
table of tblEmployee tblDeparment and tblAudit

Now create the AFTER INSERT Trigger for "tblEmployee".
Create trigger trtblEmployeeForInsert
On tblEmployee
For Insert
As 
Begin
Declare @Id int                         --Declare variable
Select @Id=Id from inserted             --select Id from Inserted table which copy of actual insert data of actaual table and pass to @Id
Insert into tblAudit values('New Employee with Id=' + CAST(@Id as nvarchar(10))+ 'is added at='+ CAST(GETDATE() as nvarchar(20)) )   --insert into tblAudit 

--CAST is used to convert int type Id to nvarchar that concatenate with "New Employee with Id"
End

Now insert data into “tblEmployee” than "trtblEmployeeForInsert" trigger automatically fire and data insert into "tblAudit" and also show in message for two row affected.
insert into tblEmployee values('Collie', 'Male', 2)
insert data into tblEmployee

Now Check data from tables.
data of tbleEmployee tblDepartment and tblAudit

Above Query save data in "trtblEmployeeForInsert" trigger with id and date.


EXAMPLE 2
For more understand about AFTER INSERT Trigger we create take another trigger example.
First we create another table that hold all activity of main table done by user
Create table tblAuditDetailsBy
(
  Id int not null Primary key identity(1,1),
  EmpId int Not Null,
  EmpName varchar(30) Not Null,
  Gender char(8) Not Null,
  DeparmentId int Not Null,
  AuditAction varchar(30) Not Null,
  ActionTakenBy varchar(50) Not Null,
  AuditTime datetime not null default Getdate(),
  ServerName varchar(100) Not Null,
  ServerInstanceName varchar(100) Not Null
)
Now create AFTER INSERT trigger
CREATE TRIGGER trtblEmployeeForAfterInsert
On tblEmployee
AFTER INSERT                 -- We can use AFTER instead of FOR, in above Query we use FOR
AS
 Begin
 declare @EmpId int;
 declare @EmpName varchar(30);
 declare @EmpGender varchar(8);
 declare @EmpDepartmentId int;
 declare @EmpAuditAction varchar(100);
 declare @ActionTakenBy varchar(100);
        declare @ServerName varchar(100);
        declare @ServerInstanceName varchar(100);
    
 select @EmpId=I.Id from inserted I; 
 select @EmpName=I.Name from inserted I; 
 select @EmpGender=I.Gender from inserted I;
 select @EmpDepartmentId=I.DeparmentId from inserted I; 
 set @EmpAuditAction='Inserted Record ';
 set @ActionTakenBy = SYSTEM_USER;
 set @ServerName = CAST( SERVERPROPERTY('ServerName') AS VARCHAR(50));          -- select @@SERVERNAME return server name
 set @ServerInstanceName = CAST( SERVERPROPERTY('MachineName') AS VARCHAR(50));    --SELECT @@servicename return current machine name
 
 insert into tblAuditDetailsBy (EmpId, EmpName, Gender, DeparmentId, AuditAction,
                                ActionTakenBy, AuditTime,ServerName,ServerInstanceName)
                         values(@EmpId,@EmpName,@EmpGender,@EmpDepartmentId,@EmpAuditAction,
                                @ActionTakenBy,GETDATE(), @ServerName, @ServerInstanceName)

 PRINT 'Successfully Fired the AFTER INSERT Triggers in SQL Server'
End
Now insert data into “tblEmployee” than "trtblEmployeeForAfterInsert" trigger automatically fire and data insert into "tblAuditDetailsBy" and also show in message for two row affected.
insert into tblEmployee values('Janiffer', 'Female', 3)
insert data into tblEmployee

Now check data from tables
select data of trigger

Triggers and Types in sql server


What is trigger

Triggers is a special type of database operation (In many way it is similar to a stored procedure) which execute automatically when perform DML (INSERT, UPDATE, DELETE) operation on the table or views or perform DDL (CREATE, AKTER, DROP) operation on Table, Function, Index, Store Procedure or a database operation (LOGON, LOGOFF).
Each table or views has its own triggers and you can't execute trigger explicitly.

Type of Trigger in sql


AFTER Triggers (For Triggers)

AFTER Triggers fire after the triggering action (Insert, Update, delete) but before the statement's competition to the databases. AFTER triggers has the ability that it can rollback modification action or statements.
e.g. If we insert a row into a table and a trigger associated with that insert event on the table will fire only after the row passes perfectly (with primary key, constraints etc.). If insertion fails due to any reason, then SQL Server will not fire the AFTER Trigger.

Note:-
1. AFTER trigger can only use with table not views.
2. A single AFTER trigger can use with single table.
3. The text, ntext, and image columns cannot be referenced in the AFTER trigger logic.

INSTEAD OF Triggers

INSTEAD OF Triggers fire instead of any of the Insert, Update or Delete operations i.e this trigger fire before SQL Server starts the execution of the action. If We have an INSTEAD OF insert/update/delete trigger on a table that successfully executed but does not include the actual insert/update/delet to the table.
e.g. If we apply an INSTEAD OF trigger on a table for the delete operation, and we try to delete rows from the table, they will not actually get deleted.

Note:-
1. We can define an INSTEAD OF trigger on a view. When multiple base table need to update than use view in trigger.
2. INSTEAD OF trigger replace the actions of the original data modification that fired the trigger.
3. Constraint(Foreign key, check, unique, primary) happens after the INSTEAD OF trigger fires.

DDL Trigger

DDL Trigger fire in response to DDL Events (when Create, Alter, Drop (Table, Function, Index, Store Procedure)) then corresponding event fired.
e.g. when you create a table using create DDL statement, associate event is "create_table", that event is raised. And you have trigger that associate with that event than, when you create a table that associate table is fired.
Similarly when drop a store procedure than "Drop_storeprocedure" is fire, when create a function DDL function event is raised.

DDL Triggers can be DATABASE scoped (CREATE TABLE, CREATE PROCEDURE, CREATE FUNCTION, ALTER TABLE, ALTER PROCEDURE, ALTER FUNCTION etc.) or SERVER scoped (CREATE DATABASE, CREATE LOGIN, GRANT_SERVER, ALTER DATABASE, ALTER LOGIN etc.).

Use of DDL Trigger

If you want to execute some code in response to a specific DDL Event To prevent certain changes to your database schema. Audit the changes that the users are making to the database structure.

Note:-
1. We can use only FOR/AFTER clause in DDL Triggers not INSTEAD OF clause.
2. List of all list of DDL events

LOGON Trigger

Logon Trigger fire when login event occurs. LOGON Trigger fire after authentication phase of logging finishes, but before the user session is established. This Trigger control server sessions such as
1. Tracking login activity.
2. Restricting Login to SQL Server.
3. Limiting number of session for specific login.

CLR Trigger

CLR Trigger allows for the database objects (such as trigger both DDL and DML) to be coded in .NET using c#, VB. CLR Trigger is based on CLR. CLR introduce with SQL Server 2008