Posts
83
Comments
600
Trackbacks
40
February 2007 Entries
Collecting Requirements For Key Information

I've been asked to assist (this time BEFORE Project initiation for a change) in the developmennt of a new application.  The Business Liason/Tech group that is doing this has been collecting requirements (basically reviewing an EXCEL Spreadsheet on steriods) and is coming up with a data model.  We will be doing a model review, but I was able to guide them in how to record the information so I can leverage the data to generate the tables.  I've done this several times already, and they are still fine tuning the table defintion.  I then take that document (Excel, again) and generate the DDL and drop it into ERWin (I'll post that code later).

Now they are curious on how to define relationships, Primary Keys and Alternate keys.  I decided to figure out the best way to guide them in documenting this so I could leverage that as well.  So I came up with the following.  Just ask your Business Liason group to record the information in the following form, then just use the code below and generate all of your code.

Basically, you need a spreadsheet with the follwoing information

Parent Table, Key Column, Child Table, Key Type, Key Order and  Key Sequence.

Parent Table as it implies is the Parent in a relationship.  For Alterante Keys, Primary Keys it is the table that key info is being generated for.  Key Column is the Column that will be used in the key.  Child Table as is implied the child of a relationship.  It is only used for a Foreign Key type.  Key Type is P for Primary, F for Foreign Key amd A for an Alternate Key.  Key Order defines the Order of Columns in a key, and finally Key Sequence defines the Order in which Foreign or Alternate keys are created.  It is also used as part of the index or constraint.

I have been on the wrong end of documentation gone bad too many times, and there is immense push back when you tell them you can't use it...OK, you can use, you have to read it, then retype everything that they already typed. 

I hope you find this useful.

 

CREATE TABLE myTable99 (
   Parent  sysname
 , keyColumn  sysname
 , Child  sysname
 , keyType  char(1)
 , keyOrder  int
 , keySequence  int)
GO

INSERT INTO myTable99(Parent, keyColumn, Child, keyType, keyOrder, keySequence)
SELECT 'myEmployee',  'EMPL_ID', 'myDirectory', 'F', 1, 1 UNION ALL
SELECT 'myEmployee',  'EMPL_ID', ''           , 'P', 1, 1 UNION ALL
SELECT 'myEmployee',  'SSN'    , ''           , 'A', 1, 1 UNION ALL
SELECT 'myDirectory', 'PHONE'  , ''           , 'P', 1, 1 UNION ALL
SELECT 'myDirectory', 'EMPL_ID', ''           , 'P', 2, 1
GO

SELECT * FROM myTable99
GO

CREATE TABLE myEmployee(EMPL_ID char(12) NOT NULL, SSN char(9), EMP_NAME varchar(50))
CREATE TABLE myDirectory(PHONE char(10) NOT NULL, EMPL_ID char(12) NOT NULL)
GO

SELECT SQL FROM (
SELECT DISTINCT 'ALTER TABLE ' + Parent
 + ' WITH NOCHECK ADD CONSTRAINT '
 + Parent + '_PK PRIMARY KEY (' AS SQL
 , Parent, 1 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'P'
UNION ALL
SELECT '   '+keyColumn AS SQL
 , Parent, 2 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder = 1
   AND keyType = 'P'
UNION ALL
SELECT ' , '+keyColumn AS SQL
 , Parent, 3 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder <> 1
   AND keyType = 'P'
UNION ALL
SELECT DISTINCT ' )' AS SQL
 , Parent, 4 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'P'
UNION ALL
SELECT DISTINCT 'GO' AS SQL
 , Parent, 5 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'P') AS XXX
ORDER BY Parent, SQL_GROUP, keyOrder


/* Produces
 
ALTER TABLE myDirectory WITH NOCHECK ADD CONSTRAINT myDirectory_PK PRIMARY KEY (
   PHONE
 , EMPL_ID
 )
GO
ALTER TABLE myEmployee WITH NOCHECK ADD CONSTRAINT myEmployee_PK PRIMARY KEY (
   EMPL_ID
 )
GO

*/

SELECT SQL FROM (
SELECT DISTINCT 'CREATE UNIQUE INDEX '
 + Parent + '_AK'+CONVERT(varchar(3),keySequence)+' ON ' + Parent + ' ( ' AS SQL
 , Parent, 1 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'A'
UNION ALL
SELECT '   '+keyColumn AS SQL
 , Parent, 2 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder = 1
   AND keyType = 'A'
UNION ALL
SELECT ' , '+keyColumn AS SQL
 , Parent, 3 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder <> 1
   AND keyType = 'A'
UNION ALL
SELECT DISTINCT ' )' AS SQL
 , Parent, 4 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'A'
UNION ALL
SELECT DISTINCT 'GO' AS SQL
 , Parent, 5 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'A') AS XXX
ORDER BY Parent, SQL_GROUP, keyOrder


/* Produces

CREATE UNIQUE INDEX myEmployee_AK1 ON myEmployee (
   SSN
 )
GO

*/

SELECT SQL FROM (
SELECT DISTINCT 'ALTER TABLE ' + Child + ' ADD FOREIGN KEY (' AS SQL
 , Parent, 1 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'F'
UNION ALL
SELECT '   '+keyColumn AS SQL
 , Parent,  2 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder = 1
   AND keyType = 'F'
UNION ALL
SELECT ' , '+keyColumn AS SQL
 , Parent,  3 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder <> 1
   AND keyType = 'F'
UNION ALL
SELECT DISTINCT ' )' AS SQL
 , Parent,  4 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'F'
UNION ALL
SELECT DISTINCT 'REFERENCES ' + Parent + ' (' AS SQL
 , Parent, 5 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'F'
UNION ALL
SELECT '   '+keyColumn AS SQL
 , Parent,  6 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder = 1
   AND keyType = 'F'
UNION ALL
SELECT ' , '+keyColumn AS SQL
 , Parent,  7 AS SQL_GROUP, keyOrder
  FROM myTable99
 WHERE keyOrder <> 1
   AND keyType = 'F'
UNION ALL
SELECT DISTINCT ' )' AS SQL
 , Parent,  8 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'F'
UNION ALL
SELECT DISTINCT 'GO' AS SQL
 , Parent,  9 AS SQL_GROUP, 1 AS keyOrder
  FROM myTable99
 WHERE keyType = 'F') AS XXX
ORDER BY Parent,  SQL_GROUP, keyOrder


/*

ALTER TABLE myDirectory ADD FOREIGN KEY (
   EMPL_ID
 )
REFERENCES myEmployee (
   EMPL_ID
 )
GO


*/


DROP TABLE myTable99
DROP TABLE myEmployee, myDirectory

 

 

posted @ Thursday, February 22, 2007 1:05 PM | Feedback (0)
What'dya mean I can't TRUNCATE Tables that have RI?

So, we've gotten into the business of sanitizing or scrambling sensitive production data for development environments.  This is, for the most part, was the direction to do this for mainframe flat files.  Now comes along distributed environments, mostly 3rd party vendor applications on sql server.  You should see some of the twisted things these apps do.  Using reserved words as column names, creating tables with the same name but different owners..the list is long.

In any case, when we told the people who support this mess that we would need fixed width flat files,  they were.."but...but...we have over 1,000 tables".  Long story short, I wrote a bunch of sprocs to automate alot of the steps needed to get the data out and put it back so they could have a sanitized environment.

One of the issues we ran across was how to handle all of this with RI.  Now I guess I could have had them set up a data dictionary that show the relationships, but I choose a lazy way out.  I used the catalogs to copy all the RI to a Work table, DROP All of the RI (This is done with another sproc I have yet o post) so that it could be "replayed" after I was done with the TRUNCATES and the bcp in's.  Here's a sproc that will log all the RI for any database.  Be forewarned...it takes dynamic sql to a whole other level.  If anyone has anything simpler, I'd like to see it, but this works fine.

SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[isp_Gen_FK_code]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[isp_Gen_FK_code]
GO

CREATE procedure isp_Gen_FK_code
  @dbname varchar(255)


AS
/*

EXEC isp_Gen_FK_code
  @dbname = 'OHM_Prod'

SELECT * FROM FK_create_code

*/

 

SET NOCOUNT ON
DECLARE @tablename nvarchar(128), @column nvarchar(128), @schema nvarchar(128), @constraint nvarchar(128)
DECLARE @fktable nvarchar(128), @fkconstraint nvarchar(128), @onupdate varchar(9), @ondelete varchar(9)
DECLARE @comma char(1), @createsql nvarchar(4000), @dropsql nvarchar(4000), @truncatesql nvarchar(4000)
DECLARE @DYSQL nvarchar(4000),@ColList sysname, @ColList2 sysname

DECLARE @error_out int, @Result_Count int, @Error_Message varchar(255), @Error_Type int, @Error_Loc int, @rc int

SELECT @rc = 0
CREATE TABLE ##Key_Column_usage(Constraint_catalog sysname,CONSTRAINT_SCHEMA sysname, CONSTRAINT_NAME varchar(300)
    ,TABLE_CATALOG sysname, TABLE_SCHEMA sysname, TABLE_NAME sysname, COLUMN_NAME sysname
    ,ORDINAL_POSITION int)

SET @DYSQL = 'use '+@dbname+'
insert into ##Key_Column_usage
select '''+@dbname+'''    as CONSTRAINT_CATALOG
 ,user_name(c_obj.uid) as CONSTRAINT_SCHEMA
 ,c_obj.name    as CONSTRAINT_NAME
 ,'''+@dbname+'''    as TABLE_CATALOG
 ,user_name(t_obj.uid) as TABLE_SCHEMA
 ,t_obj.name    as TABLE_NAME
 ,col.name    as COLUMN_NAME
 ,case col.colid 
  when ref.fkey1 then 1   
  when ref.fkey2 then 2   
  when ref.fkey3 then 3   
  when ref.fkey4 then 4   
  when ref.fkey5 then 5   
  when ref.fkey6 then 6   
  when ref.fkey7 then 7   
  when ref.fkey8 then 8   
  when ref.fkey9 then 9   
  when ref.fkey10 then 10   
  when ref.fkey11 then 11   
  when ref.fkey12 then 12   
  when ref.fkey13 then 13   
  when ref.fkey14 then 14   
  when ref.fkey15 then 15   
  when ref.fkey16 then 16
 end      as ORDINAL_POSITION
from
 '+@dbname+'.dbo.sysobjects c_obj
 ,'+@dbname+'.dbo.sysobjects t_obj
 ,'+@dbname+'.dbo.syscolumns col
 ,'+@dbname+'.dbo.sysreferences  ref
where
 permissions(t_obj.id) != 0
 and c_obj.xtype in ('+'''F'''+ ')
 and t_obj.id = c_obj.parent_obj
 and t_obj.id = col.id
 and col.colid   in
 (ref.fkey1,ref.fkey2,ref.fkey3,ref.fkey4,ref.fkey5,ref.fkey6,
 ref.fkey7,ref.fkey8,ref.fkey9,ref.fkey10,ref.fkey11,ref.fkey12,
 ref.fkey13,ref.fkey14,ref.fkey15,ref.fkey16)
 and c_obj.id = ref.constid
union
 select
 '''+@dbname+'''    as CONSTRAINT_CATALOG
 ,user_name(c_obj.uid) as CONSTRAINT_SCHEMA
 ,i.name     as CONSTRAINT_NAME
 ,'''+@dbname+'''    as TABLE_CATALOG
 ,user_name(t_obj.uid) as TABLE_SCHEMA
 ,t_obj.name    as TABLE_NAME
 ,col.name    as COLUMN_NAME
 ,v.number    as ORDINAL_POSITION
from
 '+@dbname+'.dbo.sysobjects  c_obj
 ,'+@dbname+'.dbo.sysobjects  t_obj
 ,'+@dbname+'.dbo.syscolumns  col
 ,master.dbo.spt_values  v
 ,'+@dbname+'.dbo.sysindexes  i
where
 permissions(t_obj.id) != 0
 and c_obj.xtype in ('+'''UQ'''+' ,'+'''PK'''+')
 and t_obj.id = c_obj.parent_obj
 and t_obj.xtype  = '+'''U'''+'
 and t_obj.id = col.id
 and col.name = index_col(user_name(t_obj.uid)+'+'''.'''+'+t_obj.name,i.indid,v.number)
 and t_obj.id = i.id
 and c_obj.name  = i.name
 and v.number  > 0
  and v.number  <= i.keycnt
  and v.type  = '+'''P'''+''
execute sp_executesql @DYSQL


TRUNCATE TABLE FK_create_code
SET @DYSQL = 'declare cstrts cursor fast_forward read_only for
 SELECT DISTINCT
   c.[TABLE_SCHEMA]
 , c.[TABLE_NAME]
 , u.CONSTRAINT_NAME
  FROM   ' +@dbname+'.[INFORMATION_SCHEMA].[COLUMNS] c
  JOIN   ##Key_Column_usage u
    ON    c.[TABLE_NAME]      = u.[TABLE_NAME]
   AND   c.[TABlE_SCHEMA]    = u.[TABLE_SCHEMA]
   AND    c.[COLUMN_NAME]     = u.[COLUMN_NAME]
  JOIN   ' +@dbname+'.[INFORMATION_SCHEMA].[table_constraints] t
    ON    u.[CONSTRAINT_NAME] = t.[CONSTRAINT_NAME]
 WHERE    t.[CONSTRAINT_TYPE] = ' + '''FOREIGN KEY'''

execute sp_executesql @DYSQL
Select @error_out = @@error
If @error_out <> 0
  BEGIN
   SELECT @Error_Loc = 1, @Error_Type = 50001, @rc = -1
   GOTO isp_Gen_FK_code_Error
  END

OPEN cstrts

fetch next from cstrts
into @schema, @tablename, @constraint

while @@fetch_status = 0
begin

SET @DYSQL = 'DECLARE @cr nchar(2), @go nvarchar(8)
SET @cr = nchar(13)+nchar(10)
SET @go = @cr + '+'''GO'''+' + @cr

SELECT DISTINCT
   @fktable = u2.[TABLE_NAME]
 , @fkconstraint = r.[UNIQUE_CONSTRAINT_NAME]
 , @onupdate = r.[UPDATE_RULE]
 , @ondelete = r.[DELETE_RULE]
 --, @column = u.[COLUMN_NAME]
  FROM ' +@dbname+'.[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS] r
  JOIN ##Key_Column_usage u2
    ON r.[UNIQUE_CONSTRAINT_NAME] = u2.[CONSTRAINT_NAME]
  JOIN ##Key_Column_usage u
    ON u.[CONSTRAINT_NAME] = r.[CONSTRAINT_NAME]
 WHERE r.[CONSTRAINT_NAME] = @constraint


SELECT @ColList = Null

select @ColList = COALESCE(@ColList + '+ ''','''+ ', '+'''''' +') + '
     +'''['''+' +CAST(COLUMN_NAME AS sysname)+'+''']'''+'
FROM (SELECT DISTINCT TOP 100 u.COLUMN_NAME, u.[ORDINAL_POSITION]
        FROM ' +@dbname+'.[INFORMATION_SCHEMA].[REFERENTIAL_CONSTRAINTS] r
        JOIN ##Key_Column_usage u2
          ON r.[UNIQUE_CONSTRAINT_NAME] = u2.[CONSTRAINT_NAME]
        JOIN ##Key_Column_usage u
          ON u.[CONSTRAINT_NAME] = r.[CONSTRAINT_NAME]
       WHERE r.[CONSTRAINT_NAME] = @constraint
    ORDER BY u.[ORDINAL_POSITION]
) AS XXX
set @createsql =
'+ '''ALTER TABLE ['+@dbname+'].[''' +'
+ @schema
+ '+'''].['''+'
+ @tablename
+ '+'''] ADD CONSTRAINT ['''+'
+ @constraint
+ '+'''] '''+'
+ @cr
+ '+'''FOREIGN KEY ('''+'
+ @colList
+ '+''') REFERENCES ['+@dbname+'].[''' +'
+ @schema
+ '+'''].['''+'
+ @fktable
+ '+'''] ('''+'

CREATE TABLE #Ver(Dbversion varchar(2000))
INSERT INTO #Ver
SELECT @@Version

 

 SELECT @ColList2 = Null

  select @ColList2 = COALESCE(@ColList2 + '+ ''','''+ ', '+'''''' +') + '
     +'''['''+' +CAST(c.COLUMN_NAME AS sysname)+'+''']'''+'
    FROM ' +@dbname+'.[INFORMATION_SCHEMA].[COLUMNS] c
    JOIN ##Key_Column_usage u
      ON c.[TABLE_NAME] = u.[TABLE_NAME]
     AND c.[COLUMN_NAME] = u.[COLUMN_NAME]
   WHERE u.[CONSTRAINT_NAME] = @fkconstraint
     AND u.[CONSTRAINT_SCHEMA] = c.[TABLE_SCHEMA]
ORDER BY u.[ORDINAL_POSITION]

set @createsql = @createsql + @colList2

IF EXISTS(SELECT * FROM #Ver where dbversion like '+ '''%8.00%'''+')
BEGIN

set @createsql = @createsql + '+''') ON DELETE '''+'
+ @ondelete
+ '+''' ON UPDATE '''+'
+ @onupdate
END
ELSE
BEGIN
set @createsql = @createsql + '+''')'''+'
END

INSERT INTO FK_Create_code (FK_Code)
VALUES (@createsql)

--print @createsql'


execute sp_executesql @DYSQL,N' @tablename nvarchar(128), @column nvarchar(128), @schema nvarchar(128), @constraint nvarchar(128)
 ,@fktable nvarchar(128), @fkconstraint nvarchar(128), @onupdate varchar(9), @ondelete varchar(9)
, @comma char(1), @createsql nvarchar(4000), @dropsql nvarchar(4000), @truncatesql nvarchar(4000),@ColList nvarchar(300)
, @colList2 nvarchar(300)'
,@tablename,@column,@schema, @constraint, @fktable, @fkconstraint , @onupdate, @ondelete, @comma, @createsql
, @dropsql, @truncatesql, @ColList, @colList2


Select @error_out = @@error
If @error_out <> 0
  BEGIN
   SELECT @Error_Loc = 1, @Error_Type = 50001, @rc = -1
   GOTO isp_Gen_FK_code_Error
  END

 

fetch next from cstrts
into @schema, @tablename, @constraint

end

isp_Gen_FK_code_Exit:
close cstrts
deallocate cstrts
DROP TABLE ##KEY_column_usage
RETURN @rc
SET NOCOUNT OFF

isp_Gen_FK_code_Error:


If @Error_Type = 50001
 BEGIN
  Select @error_message = (Select 'Location: ' + ',"' + RTrim(Convert(char(3),@Error_Loc)) 
          + ',"' + '  @@ERROR: ' + ',"' + RTrim(Convert(char(6),error))
          + ',"' + ' Severity: ' + ',"' + RTrim(Convert(char(3),severity))
          + ',"' + '  Message: ' + ',"' + RTrim(description)
          From master..sysmessages
        Where error = @error_out)
 END

RAISERROR @Error_Type @Error_Message

GOTO isp_Gen_FK_code_Exit

 


GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS ON
GO

 

posted @ Tuesday, February 20, 2007 11:58 AM | Feedback (2)
SET Versus SELECT (Or, Who Really Cares Anyway)

EDIT:  As Tara points out:

Vyas did this test quite some time ago: http://vyaskn.tripod.com/differences_between_set_and_select.htm Either I never read it, or I forgot I read it.  Well hopefully I pulled some different points together differently here than Vyas did, and at the very least, I hope I made my feeling clear about a program that has to loop over 2 million times.  Thanks for the heads up Tara...                                     

OK, this always comes up from time to time, and it always seem that people are both sides of the fence. "SET is faster because....", "No, SELECT is faster because".  Well there should be no debate about it, yet I've failed to find a definitive explanation of what the true story behind this is.  In any case I've wanted to look into this.

In this thread the question comes up again.  In that thread, Peter posts a link to a SQL Server Magazinee Article that discusses this topic.  While it was a good read, I had a hard time buying it.  The author (who is listed as "Reader") posted that in using SET, it is optimized and when a single value is set that this is more effecient.  They then go on to say that after 1 million iterations with multiple value stes, SELECT was 59% more effecient for each operation.  Now the fact that they are doing checks between each assignment seems to cause a potential unexpected interference by SQL server to the outcome of the results.  Now, in above article, the first line states "Loops are fairly common in SQL Server stored procedures. ", which in itself is sort of a red herring, since if you are coding that way, I would sugest that you step back and rethink your process.  If you can't find a set based solution for 99% for what you have to do, then drop me a line,  or head on over to SQL Team.

So I set forth for my own test.  I did my tests with an undisturbed loop where dattime values were grabbed before and after the loops of pure sets.  I did for 1,000, 10,000, 1,000,000 and 10,000,000.  Looking Kalen's book (Inside SQL Server 2000), she has a chapter th differences between the two, but nothing about performance.  I'll need to google around some more, however,  there must be an explanation about the internals.  I did the test for Multiple variable assignments, and another set for single variable assignments.  For the 1 million iteration (and it's really 2 million assignments)  I got the following:

SELECT_MS_Multiple  SET_MS_Multiple
------------------                  ---------------
43470                              202963

SELECT_MS_Single   SET_MS_Single
----------------                    -------------
42453                             45746

Now in both Cases, SELECT wins, in the case of Multiple assignments, SELECT seems to blow SET's doors off.  Now, I need to reiterate this again.  If you are finding that you have a process that needs to loop 1 million times, you either are backed into a corner due to previous developement that can't be changed, you've run into the 1% of the time that you have to, or you have a flawed application design. 

If Anyone sees anyuthing wrong with this test, or  if anyone has any comments I would look forward to it.  With all that said, I use SELECT almost exclusively.  Here's the code:

DECLARE   @SET1 int,      @SELECT1 int,      @SET2 int,           @SELECT2 int
DECLARE   @SET3 int,      @SELECT3 int,      @SET4 char,          @SELECT4 char
DECLARE   @SET5 char,     @SELECT5 char,     @SET6 char,          @SELECT6 char
DECLARE   @SET7 datetime, @SELECT7 datetime, @SET8 datetime,      @SELECT8 datetime
DECLARE   @SET9 datetime, @SELECT9 datetime, @SETA varchar(8000), @SELECTA varchar(8000)

DECLARE @x int, @s1 datetime, @s2 datetime, @e1 datetime, @e2 datetime, @c int
DECLARE @s3 datetime, @s4 datetime, @e3 datetime, @e4 datetime

SELECT @x = 1, @s1 = getDate(), @c = 1000000

WHILE @x < @c
  BEGIN
 SELECT    @SELECT1 = 1
  , @SELECT2 = 2
  , @SELECT3 = 3
  , @SELECT4 = 'a'
  , @SELECT5 = 'b'
  , @SELECT6 = 'c'
  , @SELECT7 = '2001-09-11'
  , @SELECT8 = GetDate()
  , @SELECT9 = '1999-12-31'
  , @SELECTA = 'This is a test of the emergency Broadcationg System.  This is only a test'

 SELECT    @SELECT1 = 0
  , @SELECT2 = 0
  , @SELECT3 = 0
  , @SELECT4 = ''
  , @SELECT5 = ''
  , @SELECT6 = ''
  , @SELECT7 = ''
  , @SELECT8 = 0
  , @SELECT9 = 0
  , @SELECTA = ''
 
 SET @x = @x + 1
  END

SELECT @x = 1, @s2 = getDate(), @e1 = getDate()

WHILE @x < @c
  BEGIN
 SET       @SELECT1 = 1
 SET   @SELECT2 = 2
 SET    @SELECT3 = 3
 SET   @SELECT4 = 'a'
 SET   @SELECT5 = 'b'
 SET   @SELECT6 = 'c'
 SET   @SELECT7 = '2001-09-11'
 SET   @SELECT8 = GetDate()
 SET   @SELECT9 = '1999-12-31'
 SET    @SELECTA = 'This is a test of the emergency Broadcationg System.  This is only a test'

 SET       @SELECT1 = 0
 SET   @SELECT2 = 0
 SET    @SELECT3 = 0
 SET   @SELECT4 = ''
 SET   @SELECT5 = ''
 SET   @SELECT6 = ''
 SET   @SELECT7 = 0
 SET   @SELECT8 = 0
 SET   @SELECT9 = 0
 SET    @SELECTA = ''
 
 SET @x = @x + 1
  END

SELECT @e2 = getDate()


SELECT @x = 1, @s3 = getDate()

WHILE @x < @c
  BEGIN
 SELECT    @SELECT1 = 1

 SELECT    @SELECT1 = 0

 SET @x = @x + 1
  END

SELECT @x = 1, @s4 = getDate(), @e3 = getDate()

WHILE @x < @c
  BEGIN
 SET       @SELECT1 = 1

 SET       @SELECT1 = 0
 
 SET @x = @x + 1
  END

SELECT @e4 = getDate()


SELECT DATEDIFF(ms,@s1,@e1) AS SELECT_MS_Multiple, DATEDIFF(ms,@s2,@e2) AS SET_MS_Multiple
SELECT DATEDIFF(ms,@s3,@e3) AS SELECT_MS_Single, DATEDIFF(ms,@s4,@e4) AS SET_MS_Single

 

posted @ Monday, February 12, 2007 2:36 PM | Feedback (3)
3rd and 45? Drop back and Punt? Nah, Generate INSERTS

EDIT 2007/09/06:  I've modified the sproc to change the dates to be formatted to 121 and stripped out all trailing spaces for char's

So, we don't have DBArtisan, but I am very happy for my copy of ERWin.  Don't know what I'd do with out it.

So we have some requirements where they want to create insert statements to load a production table.  I said, why not just bcp the data out in native format and create an osql script for the production DBA's to insert the data, or a sproc perhaps.

There are many better ways in my opinion, but I do like a challenge, so I wrote the following.  It's not a very mature sproc...no error handling, doesn't handle images or text (how would you anyway for inserts?), ect

 

Just supply the table_name to the sproc

 

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[isp_Generate_Inserts]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[isp_Generate_Inserts]
GO

CREATE PROC isp_Generate_Inserts
 @TABLE_NAME sysname
AS

SET NOCOUNT ON

/*
EXEC isp_Generate_Inserts 'BusinessGroup'
EXEC isp_Generate_Inserts 'MEPType'
EXEC isp_Generate_Inserts 'Person'
EXEC isp_Generate_Inserts 'Profile'
EXEC isp_Generate_Inserts 'Status'
EXEC isp_Generate_Inserts 'SubBusinessGroup'
EXEC isp_Generate_Inserts 'XREF'
EXEC isp_Generate_Inserts 'Operator'
EXEC isp_Generate_Inserts 'FORMREF'
EXEC isp_Generate_Inserts 'MEPTERRITORY'
EXEC isp_Generate_Inserts 'MEPTICKLERSTATUS'
*/

DECLARE @INSERT varchar(8000), @COLLIST varchar(8000)
--, @TABLE_NAME sysname
, @SELECT varchar(8000), @cmd varchar(8000), @x int

  SELECT @COLLIST = COALESCE(@COLLIST + ', ','') + COLUMN_NAME
    FROM INFORMATION_SCHEMA.Columns
   WHERE TABLE_NAME = @TABLE_NAME
ORDER BY ORDINAL_POSITION

SELECT @INSERT = 'INSERT INTO ' + @TABLE_NAME + '('+ @COLLIST + ')'

-- SELECT @INSERT

SELECT @SELECT = COALESCE(@SELECT + '+'',''+ ','') +
           CASE WHEN DATA_TYPE
  IN ('datetime','smalldatetime')
  THEN + ''''+ +''''+''''+''''+'+' + 'COALESCE(CONVERT(varchar(25),' + COLUMN_NAME + ',121),'''')' + '+' + ''''+''''+''''+'''' 
  WHEN DATA_TYPE
  NOT IN ('int','bigint','smallint','tinyint','deciaml','numeric','money')
  THEN + ''''+ ''''+''''+''''+'+COALESCE(REPLACE(RTRIM(' + COLUMN_NAME + ')' + ','''''''','''''''''''')' + ','''')+' + ''''+''''+''''+''''
  ELSE + 'COALESCE(RTRIM(CONVERT(varchar(25),' + COLUMN_NAME + ')),'''''''''''')'
    END
    FROM INFORMATION_SCHEMA.Columns
   WHERE TABLE_NAME = @TABLE_NAME
ORDER BY ORDINAL_POSITION

SELECT @SELECT = 'SELECT ' + @SELECT + ' AS DATA FROM ' + @TABLE_NAME

-- SELECT @SELECT

SET @cmd = 'CREATE VIEW XXX AS ' + @SELECT

EXEC(@cmd)

CREATE TABLE myTable99(RowId int IDENTITY(1,1), Data varchar(8000))

INSERT INTO myTable99(Data) SELECT DATA FROM XXX

SELECT 0 AS RowId, @INSERT AS DATA INTO myTemp99

SET @cmd = 'CREATE VIEW YYY AS '
+'SELECT RowId, DATA FROM myTemp99 '
+'UNION ALL '
+'SELECT RowId, '+ '''' + 'SELECT ' + '''' + ' + DATA+ ' + '''' + ' UNION ALL ' + '''' + ' AS DATA FROM myTable99 WHERE RowId < (SELECT COUNT(*) FROM myTable99)'
+'UNION ALL '
+'SELECT RowId, '+ '''' + 'SELECT ' + '''' + ' + DATA AS DATA FROM myTable99 WHERE RowId = (SELECT COUNT(*) FROM myTable99) '

-- SELECT @cmd

EXEC(@cmd)

SET @cmd = 'bcp "SELECT DATA FROM MEP.dbo.YYY ORDER BY RowId" QUERYOUT D:\MEP\Scripts\INS_'+@TABLE_NAME+'.Dat -T -c -S<servername>'

-- SELECT @cmd

EXEC master..xp_cmdshell @cmd

 DROP VIEW XXX, YYY
 DROP TABLE myTable99, myTemp99
 SET NOCOUNT OFF

EXEC master..xp_cmdshell 'Dir D:\MEP\Scripts\*.*'

GO

 

 

posted @ Thursday, February 08, 2007 2:39 PM | Feedback (0)