4

I learned how to generate script for a table.

Eg for this table:

enter image description here

to generate script like this (I omitted something):

CREATE TABLE [dbo].[singer_and_album](
    [singer] [varchar](50) NULL,
    [album_title] [varchar](100) NULL
) ON [PRIMARY]
GO

INSERT [dbo].[test_double_quote] ([singer], [album_title]) VALUES (N'Adale', N'19')
GO

INSERT [dbo].[test_double_quote] ([singer], [album_title]) VALUES (N'Michael Jaskson', N'Thriller"')
GO

I tried programmatically generating the script using this shell code. And got error:

PS SQLSERVER:\SQL\DESKTOP-KHTRJOJ\MSSQL\Databases\yzhang\Tables\dbo.test_double_quote> C:\Users\yzhang\Documents\script_out_table.ps1 "DESKTOP-KHTRJOJ\MSSQL" "yzhang" "dbo" "test_double_quote", "C:\Users\yzhang\Documents\script_out.sql"

Multiple ambiguous overloads found for "EnumScript" and the argument count: "1". At C:\Users\yzhang\Documents\script_out_table.ps1:41 char:16 + foreach ($s in $scripter.EnumScript($tbl.Urn)) { write-host $s } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodCountCouldNotFindBest

Anybody can help? I don't know much about shell. btw is shell the only way to generate scripts? Can we do it with some sql code? Thank you--


FYI, see this for how to manually generate script. In my case (sql server 2016 management studio) it's like

  1. right click the database name (not table name) -> Tasks -> Generate scripts

enter image description here

  1. choose a table or all tables

  2. click advanced and select schema and data enter image description here

4
  • which programming laguages you can code so we can provide an alternate. Commented Nov 5, 2017 at 8:49
  • Thank you @ImranAliKhan. I'm familiar with Python/R/sql. If somebody can tell me how to change the shell code, that would be nice too (I don't understand too much shell so I'll mechanically use it) Commented Nov 5, 2017 at 8:54
  • see my updated answer Commented Nov 5, 2017 at 9:02
  • There are some comments at the bottom of the article where you got the Powershell script that talk about the "multiple overloads" error and how they fixed by removing the .Urn reference: foreach ($s in $scripter.EnumScript($tbl)) Commented Nov 5, 2017 at 10:05

2 Answers 2

5

this is a sql script to genrate table script

declare @vsSQL varchar(8000)
declare @vsTableName varchar(50)
select @vsTableName = '_PRODUCT'--- Your Table Name here

select @vsSQL = 'CREATE TABLE ' + @vsTableName + char(10) + '(' + char(10)

select @vsSQL = @vsSQL + ' ' + sc.Name + ' ' +
st.Name +
case when st.Name in ('varchar','varchar','char','nchar') then '(' + cast(sc.Length as varchar) + ') ' else ' ' end +
case when sc.IsNullable = 1 then 'NULL' else 'NOT NULL' end + ',' + char(10)
from sysobjects so
join syscolumns sc on sc.id = so.id
join systypes st on st.xusertype = sc.xusertype
where so.name = @vsTableName
order by
sc.ColID

select substring(@vsSQL,1,len(@vsSQL) - 2) + char(10) + ')'

Edit: c# code

public string GetScript(string strConnectionString
                      , string strObject
                      , int ObjType)
{
    string strScript = null;
    int intCounter = 0;
    if (ObjType != 0)
    {
        ObjSqlConnection = new SqlConnection(strConnectionString.Trim());

        try
        {
            ObjDataSet = new DataSet();
            ObjSqlCommand = new SqlCommand("exec sp_helptext 
                [" + strObject + "]", ObjSqlConnection);
            ObjSqlDataAdapter = new SqlDataAdapter();
            ObjSqlDataAdapter.SelectCommand = ObjSqlCommand;
            ObjSqlDataAdapter.Fill(ObjDataSet);

            foreach (DataRow ObjDataRow in ObjDataSet.Tables[0].Rows)
            {
                strScript += Convert.ToString(ObjDataSet.Tables[0].Rows[intCounter][0]);
                intCounter++;
            }
        }
        catch (Exception ex)
        {
           strScript = ex.Message.ToString();
        }
        finally
        {
            ObjSqlDataAdapter = null;
            ObjSqlCommand = null;
            ObjSqlConnection = null;
        }
    }

    return strScript;
}

To create Insert script use this store procedure

IF EXISTS (SELECT * FROM dbo.sysobjects 
WHERE id = OBJECT_ID(N'[dbo].[InsertGenerator]') AND OBJECTPROPERTY(id,N'IsProcedure') = 1)
DROP PROCEDURE [dbo].[InsertGenerator]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER OFF
GO

CREATE PROC [dbo].[InsertGenerator]
(
@tableName varchar(100),
@KeyColumn1 varchar(100)='',
@KeyColumn2 varchar(100)=''
)
AS

-- Generating INSERT statements in SQL Server
-- to validate if record exists - supports 2 field Unique index

--Declare a cursor to retrieve column specific information for the specified table
DECLARE cursCol CURSOR FAST_FORWARD FOR 
SELECT column_name,data_type FROM information_schema.columns WHERE table_name = @tableName

OPEN cursCol

DECLARE @string nvarchar(max) --for storing the first half of INSERT statement
DECLARE @stringData nvarchar(max) --for storing the data (VALUES) related statement
DECLARE @dataType nvarchar(1000) --data types returned for respective columns
DECLARE @FieldVal nvarchar(1000) -- save value for the current field
DECLARE @KeyVal nvarchar(1000) -- save value for the current field
DECLARE @KeyTest0 nvarchar(1000) -- used to test if key exists
DECLARE @KeyTest1 nvarchar(1000) -- used to test if key exists
DECLARE @KeyTest2 nvarchar(1000) -- used to test if key exists

SET @KeyTest0=''

IF @KeyColumn1<>''
SET @KeyTest0='IF not exists (Select * from '+@tableName

SET @KeyTest1=''
SET @KeyTest2=''

SET @string='INSERT '+@tableName+'('
SET @stringData=''
SET @FieldVal=''
SET @KeyVal=''

DECLARE @colName nvarchar(50)

FETCH NEXT FROM cursCol INTO @colName,@dataType

IF @@fetch_status<>0
begin
    print 'Table '+@tableName+' not found, processing skipped.'
    close curscol
    deallocate curscol
    return
END

WHILE @@FETCH_STATUS=0
BEGIN

IF @dataType in ('varchar','char','nchar','nvarchar')
BEGIN
    SET @FieldVal=''''+'''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'
    SET @KeyVal='''+isnull('''''+'''''+'+@colName+'+'''''+''''',''NULL'')+'',''+'
    SET @stringData=@stringData+@FieldVal
END

ELSE

if @dataType in ('text','ntext','xml') --if the datatype is text or something else 
BEGIN
    SET @FieldVal='''''''''+isnull(cast('+@colName+' as varchar(max)),'''')+'''''',''+'
    SET @stringData=@stringData+@FieldVal
END
ELSE
IF @dataType = 'money' --because money doesn't get converted from varchar implicitly
BEGIN
    SET @FieldVal='''convert(money,''''''+isnull(cast('+@colName+' as varchar(200)),''0.0000'')+''''''),''+'
    SET @stringData=@stringData+@FieldVal
END
ELSE 
IF @dataType='datetime'
BEGIN
    SET @FieldVal='''convert(datetime,'+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+',121)+'''''+''''',''NULL'')+'',121),''+'
    SET @stringData=@stringData+@FieldVal
END
ELSE 
IF @dataType='image' 
BEGIN
    SET @FieldVal='''''''''+isnull(cast(convert(varbinary,'+@colName+') as varchar(6)),''0'')+'''''',''+'
    SET @stringData=@stringData+@FieldVal
END
ELSE --presuming the data type is int,bit,numeric,decimal 
BEGIN
    SET @FieldVal=''''+'''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'
    SET @KeyVal='''+isnull('''''+'''''+convert(varchar(200),'+@colName+')+'''''+''''',''NULL'')+'',''+'
    SET @stringData=@stringData+@FieldVal
END

--Build key test
IF @KeyColumn1=@colName
begin
    SET @KeyTest1 = ' WHERE [' + @KeyColumn1 + ']='
    SET @KeyTest1 = @KeyTest1+@KeyVal+']'
end
IF @KeyColumn2=@colName
begin
    SET @KeyTest2 = ' AND [' + @KeyColumn2 + ']='
    SET @KeyTest2 = @KeyTest2+@KeyVal+']'
end

SET @string=@string+'['+@colName+'],'

FETCH NEXT FROM cursCol INTO @colName,@dataType
END

DECLARE @Query nvarchar(max)

-- Build the test string to check if record exists
if @KeyTest0<>''
begin
    if @Keycolumn1<>''
        SET @KeyTest0 = @KeyTest0 + substring(@KeyTest1,0,len(@KeyTest1)-4)
    if @Keycolumn2<>''
    begin
        SET @KeyTest0 = @KeyTest0 + ''''
        SET @KeyTest0 = @KeyTest0 + substring(@KeyTest2,0,len(@KeyTest2)-4)
    end
    SET @KeyTest0 = @KeyTest0 + ''')'

    SET @query ='SELECT '''+substring(@KeyTest0,0,len(@KeyTest0)) + ') ' 
end
else
    SET @query ='SELECT '''+substring(@KeyTest0,0,len(@KeyTest0))

SET @query = @query + substring(@string,0,len(@string)) + ') ' 
SET @query = @query + 'VALUES(''+ ' + substring(@stringData,0,len(@stringData)-2)+'''+'')'' FROM '+@tableName

exec sp_executesql @query

CLOSE cursCol
DEALLOCATE cursCol

GO

and use of InsertGenerator like below

DECLARE @return_value int

EXEC    @return_value = [dbo].[InsertGenerator]
        @tableName = N'_PRODUCT'

SELECT  'Return Value' = @return_value
Sign up to request clarification or add additional context in comments.

2 Comments

thank you so much @ImranAliKhan. I suggest you leave the c# code there, so it can help someone else. I tested this code, it generates the code to make the table schema perfectly, but not to insert the data. Could you please add that part too, if possible? A maybe bigger problem is, the output string is a variable - my data has 20G I'm concerned about the length. I'll do some research about it too. Thank you so much-
Hi @ImranAliKhan I am also looking similar problem, need to generate selective stored procedures (300+) and generate script programmatically as it could be done many times. Can you please provide a solution so it all goes to one text file.
1

Expanding upon Imran Ali Khan's answer to

  • properly handle text datatypes (his had typo varchar instead of nvarchar)
  • handle max text length type
  • handle numeric/decimal datatype's precision and scale
  • handle computed columns
  • add the IDENTITY(1,1) and named primary keys at the end as SSMS does
  • use the correct datatype for table name nvarchar(128)
  • use nvarchar(max) instead of varchar(8000) for outputting large tables

The output formatting is similar to SSMS scripting output.

declare @crlf nchar(2);
set @crlf = char(13) + char(10);
declare @createScript nvarchar(max)
declare @tableName nvarchar(128)
select @tableName = N'singer_and_album'--- Your Table Name here

select @createScript = N'CREATE TABLE [dbo].[' + @tableName + N'](' + @crlf

select @createScript = @createScript + char(9) + N'[' + sc.[name] + N'] ' +
case when sc.is_computed = 1 then
    N' AS ' + cc.[definition]
else
    st.[name] +
    case
        when st.[name] in ('varchar','nvarchar','char','nchar') then '(' + case when sc.max_length = -1 then N'max' else cast(sc.max_length as varchar) end + N')'
        when st.[name] in ('decimal','numeric') then N'(' + cast(sc.precision as varchar) + N',' + cast(sc.scale as varchar) + N')'
        else N''
    end +
    case when sc.is_identity = 1 then N' IDENTITY(1,1) ' else N' ' end +
    case when sc.is_nullable = 1 then N'NULL' else N'NOT NULL' end
end +
N',' + @crlf
from sys.columns sc
join sys.types st on st.user_type_id = sc.user_type_id
left outer join sys.computed_columns cc on cc.[object_id] = sc.[object_id] and cc.column_id = sc.[column_id]
where sc.[object_id] = object_id(@tableName)
order by
sc.column_id;
set @createScript = left(@createScript,len(@createScript) - 3); -- trim last comma

if exists(select * from sys.indexes where [object_id] = object_id(@tableName) and is_primary_key = 1)
begin
    set @createScript = @createScript + N',' + @crlf + N' CONSTRAINT [' +
    (select top 1 [name] from sys.indexes where object_id = object_id(@tableName) and is_primary_key = 1) + N'] PRIMARY KEY CLUSTERED ' + @crlf + N'(' + @crlf;

    select @createScript = @createScript +
    char(9) + N'[' + sc.[name] + N'] ' + case when ic.is_descending_key = 1 then N'DESC' else N'ASC' end + N',' + @crlf
    from sys.index_columns ic
    join sys.columns sc on ic.[object_id] = sc.[object_id] and ic.column_id = sc.column_id
    join sys.indexes si on ic.[object_id] = si.[object_id] and ic.index_id = si.index_id
    where ic.object_id = object_id(@tableName) and si.is_primary_key = 1
    order by ic.index_column_id;

    set @createScript = left(@createScript,len(@createScript) - 3) + @crlf + N')' -- trim last comma
end

select @createScript + @crlf + N')';

Known issues:

  • Assumes your table is in schema dbo
  • Assumes your identity column is IDENTITY(1,1)
  • Assumes you only have one primary key index (however it does support multiple columns)
  • Doesn't script index flags such as padding, ignore_dup_key, etc
  • Doesn't support datetime2 length other then 7 (default)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.