Recent posts
Recent comments
Author: Rajib
Calender
<<  March 2010  >>
MoTuWeThFrSaSu
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234
Blogroll

    Two things that happened today, which motivated me to write this post: 

    1. I learned a new trick using set-operation

    2. Also today is the day some of my SQL Server colleagues having #TSQL2sDay party

     

    Here is the entry where I learned the trick [http://ask.sqlteam.com/questions/1206/insert-date-value-for-1-year]. 

     

    I have been participating at AskSqlTeam.com lately. One of the recent question was about how to generate date for 1 year. TG had an interesting solution and I did not realize it was set-operation until Kristen set me straight. :) As usual, I was coming up with a iterative solution as opposed to set-based one. Here is the snippet I modified off of TG's code.

    create table #myTable 
    
    (dateCol datetime)
    
    go
    
    declare @i int
    
    SET @i = 0
    
    WHILE 
    
    (
    
     datediff(year, dateadd(day, @i,'2010-01-01'),'2010-01-01')=0
    
    )
    
    begin
    
        insert #myTable (dateCol)
    
        select dateadd(day, @i, '2010-01-01')
    
        SET @i = @i + 1
    
        continue
    
    end
    
    go
    
    select * from #myTable
    
    go
    


    The script above will create about 365 entries containing everyday of the year 2010. 

    TG's answer to that problem was:

    create table #myTable 
    
    (dateCol datetime)
    
    go
    
    insert #myTable (dateCol)
    
    select dateadd(day, number, '2010-01-01')
    
    from   master..spt_values
    
    where  type = 'P'and    number < 365
    
    order by number
    
    go
    
    select * from #myTable
    
    go
    

     

    Anyways, my approach above is not the most ideal solution and it will be slow because of the looping. TG had the right idea. Many DB professional create a reference database for their tasks. In this database one may have scripts that can be applied on scheduled jobs and other artifacts that don't belong anywhere else. The solution above can be improved if we create a reference table containing all integers. Let's say we call that table IntValues. I started building that table today and it took more than 6 hours to enter 2 billion numbers. Here is the final draft of what that script would look like.

     

    create table #myTable 
    
    (dateCol datetime)
    
    go
    
    insert #myTable (dateCol)
    
    select dateadd(day, number, '2010-01-01')
    
    from   DbReference.dbo.IntValues
    
    where  number < 365
    
    order by number
    
    go
    
    select * from #myTable
    
    go
    



    Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListFacebook

    This posting is provided "AS IS" with no warranties, and confers no rights. It does not reflect any one's opinion other than the author.

    Currently rated 5.0 by 1 people

    • Currently 5/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5

    There are times we find the need to generate the database schema. In SQL Server, it can be easily done using the graphical wizards in the Management Studio. I haven't found a way to script it to this day.

     

    However, one alternative solution to this is to combine .NET programmability feature in powershell, and SMO. With this approach you can setup a powershell script job to automate your team's database build process.

     

    Here are some basic assumptions before reading this post:

    1. SQL Server 2008 is installed

    2. Powershell is installed

    3. SMO is in the GAC (Global Assembly Cache) or you know how to register it there

    4. AdventureWorks is loaded in the database

     

    Here are the steps I took to generate script against AdventureWorks database:

     

    First of all, I went to management studio and right clicked on the AdventureWorks database to "Start Powershell"

     

    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> [reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")

    GAC    Version        Location
    ---    -------        --------
    True   v2.0.50727     C:\WINDOWS\assembly\GAC_MSIL\Microsoft.SqlServer.Smo\1...

     

    At this point, the SMO object was loaded using .NET reflection technology. Next we declare $srv variable and assign the local SQL Server 2008 instance to it. Then we assign the AdventureWorks database to the $db variable. The database object has an overloaded method namely Script(). We need to invoke that method to generate the database script. See the output below as the script is run.

     

    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> $srv = new-object("Microsoft.SqlServer.Management.Smo.Server") "(local)\sql2k8"
    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> $db = $srv.Databases["AdventureWorks"]

    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> $db

    WARNING: column "Owner" does not fit into the display and was removed.

    Name                        Status          Recovery Model   CompatLvl        Collation
    ----                           ------          --------------           ---------            ---------
    AdventureWorks       Normal          Simple                 100            SQL_Latin1_General_CP1_CI_AS


    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> $db.Script()

    CREATE DATABASE [AdventureWorks] ON  PRIMARY
    ( NAME = N'AdventureWorks_Data', FILENAME = N'C:\data\MSSQL10.SQL2K8\MSSQL\DATA\AdventureWorks_Data.mdf' , SIZE = 174080KB , MAXSIZE = UNLIMITED, FILEGROWTH =16384KB )
     LOG ON
    ( NAME = N'AdventureWorks_Log', FILENAME = N'C:\data\MSSQL10.SQL2K8\MSSQL\DATA\AdventureWorks_Log.ldf' , SIZE = 18432KB , MAXSIZE = 2048GB , FILEGROWTH = 1638
    4KB ) COLLATE SQL_Latin1_General_CP1_CI_AS
    ALTER DATABASE [AdventureWorks] SET COMPATIBILITY_LEVEL = 100
    IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
    begin
        EXEC [AdventureWorks].[dbo].[sp_fulltext_database] @action = 'enable'
    end
    ALTER DATABASE [AdventureWorks] SET ANSI_NULL_DEFAULT OFF
    ALTER DATABASE [AdventureWorks] SET ANSI_NULLS ON
    ALTER DATABASE [AdventureWorks] SET ANSI_PADDING ON
    .
    .
    .

     

    The limitation we run with the above approach is that it doesn't include the objects such as tables, stored procedures, and functions in the script. That's why we have to write a loop to iterate all the tables, procedures, checks, primary, functions, etc. Each of those classes have the Script() method and we can invoke them as we need it. 

    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> for ($i=0; $i -lt $db.Tables.Count; $i++) {$db.Tables[$i].Script()}
    .
    .
    .
     

    Yes, there are more gotchas. :(

     

    So far, we have looked into resolving this issue using 1 of the overloaded Script() method. The 2nd version of the overloaded method expects ScriptingOptions as one of the parameter. Here is how we would declare them and the options they give us.

    PS SQLSERVER:\SQL\OVERLORD\SQL2K8\Databases\AdventureWorks> $sc = new-object("Microsoft.SqlServer.Management.Smo.ScriptingOptions")

    Here is a quick list of properties we can set on the $sc (ScriptingOptions) object.


                $sc.AppendToFile = 0;
                $sc.Bindings = 1;
                $sc.Default = 1;
                $sc.DdlBodyOnly = 1;
                $sc.DriAll = 1;
                $sc.DriAllConstraints = 1;
                $sc.DriAllKeys = 1;
                $sc.DriPrimaryKey = 1;
                $sc.IncludeDatabaseContext = 1;
                $sc.IncludeDatabaseRoleMemberships = 1;
                $sc.IncludeHeaders = 1;
                $sc.IncludeIfNotExists = 1;
                $sc.Indexes = 1;
                $sc.LoginSid = 1;
                $sc.PrimaryObject = 1;
                $sc.Permissions = 1;

     

     Depending upon your need, you can set the target server version, and the output file properties as well.



    Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListFacebook

    This posting is provided "AS IS" with no warranties, and confers no rights. It does not reflect any one's opinion other than the author.

    Be the first to rate this post

    • Currently 0/5 Stars.
    • 1
    • 2
    • 3
    • 4
    • 5