Click here to Skip to main content
Click here to Skip to main content

Generate SQL INSERT commands programmatically

By , 29 Jun 2006
 

Introduction

When you use TableAdapters in C#, VS generates INSERT, SELECT, and UPDATE etc. commands for you. Other commands can be added by going into the DataSet Designer and adding commands via the Add SQL Wizard. Sometimes, however, you need additional SQL commands that contain a complete list of all the fields in the DataSet. You would also like these lists to be automatically updated whenever a change is made to the database.

The code presented here does this by using functions in the Designer code to generate such strings.

Background

I actually developed these functions because I needed to INSERT rows into a database and get the value of the Identity column on the fly as I tab through a DataGridView adding new rows.

Note that this has only been developed for simple functions, but the basics are generally applicable for other applications.

Description

The file GenerateSQL.cs contains the code for a static class GenerateSQL, which has the following functions:

  • public static string BuildAllFieldsSQL ( DataTable table )
  • Returns a list of all the columns in the DataTable in SQL format which can be used in a SELECT command etc. E.g.: CustomerID, CustomerName, ....

  • public static string BuildInsertSQL ( DataTable table )
  • Returns an INSERT command with an optional SELECT CAST statement to get the SCOPE_IDENTITY if required. E.g.: INSERT INTO tableName ( CustomerName,...) VALUES (@CustomerName,...); SELECT CAST(scope_identity() AS int ). (Note that in this example, CustomerID is an Identity so it isn't included in the string.)

  • public static SqlCommand CreateInsertCommand ( DataRow row )
  • Given a DataRow, creates an instance of SqlCommand to insert the data into the DataSet.

  • public static object InsertDataRow ( DataRow row, string connectionString )
  • Given the DataRow and a connection string, creates the SqlCommand as above and executes it, returning the identity of the record.

    For example, if the Dataset Sesigner has defined a row like:

    QfrsDataSet.MembersRow row;

    I can insert it into the database, getting the identity with the statement:

    int id = (int) GenSQL.GenerateSQL.InsertDataRow ( row, connectionString );

Here is the complete code:

using System;
using System.Text;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;

namespace GenSQL
{
  public static class GenerateSQL
  {
    // Returns a string containing all the fields in the table

    public static string BuildAllFieldsSQL ( DataTable table )
    {
      string sql = "";
      foreach ( DataColumn column in table.Columns )
      {
        if ( sql.Length > 0 )
          sql += ", ";
         sql += column.ColumnName;
      }
      return sql;
                }

    // Returns a SQL INSERT command. Assumes autoincrement is identity (optional)

  public static string BuildInsertSQL ( DataTable table )
  {
    StringBuilder sql = new StringBuilder ( "INSERT INTO " + table.TableName + " (" );
    StringBuilder values = new StringBuilder ( "VALUES (" );
    bool bFirst = true;
    bool bIdentity = false;
    string identityType = null;

    foreach ( DataColumn column in table.Columns )
    {
      if ( column.AutoIncrement )
      {
        bIdentity = true;

        switch ( column.DataType.Name )
        {
          case "Int16":
            identityType = "smallint";
            break;
          case "SByte":
            identityType = "tinyint";
            break;
          case "Int64":
            identityType = "bigint";
            break;
          case "Decimal":
            identityType = "decimal";
            break;
          default:
            identityType = "int";
          break;
         }
      }
      else
      {
        if ( bFirst )
          bFirst = false;
        else
        {
          sql.Append ( ", " );
          values.Append ( ", " );
        }

        sql.Append ( column.ColumnName );
       values.Append ( "@" );
        values.Append ( column.ColumnName );
      }
    }
    sql.Append ( ") " );
    sql.Append ( values.ToString () );
    sql.Append ( ")" );

    if ( bIdentity )
    {
      sql.Append ( "; SELECT CAST(scope_identity() AS " );
      sql.Append ( identityType );
      sql.Append ( ")" );
    }

    return sql.ToString (); ;
  }


    // Creates a SqlParameter and adds it to the command

    public static void InsertParameter ( SqlCommand command,
                                         string parameterName,
                                         string sourceColumn,
                                         object value )
    {
      SqlParameter parameter = new SqlParameter ( parameterName, value );

      parameter.Direction = ParameterDirection.Input;
      parameter.ParameterName = parameterName;
      parameter.SourceColumn = sourceColumn;
      parameter.SourceVersion = DataRowVersion.Current;

      command.Parameters.Add ( parameter );
    }

    // Creates a SqlCommand for inserting a DataRow
    public static SqlCommand CreateInsertCommand ( DataRow row )
    {
      DataTable table = row.Table;
      string sql = BuildInsertSQL ( table );
      SqlCommand command = new SqlCommand ( sql );
      command.CommandType = System.Data.CommandType.Text;

      foreach ( DataColumn column in table.Columns )
      {
        if ( !column.AutoIncrement )
        {
          string parameterName = "@" + column.ColumnName;
          InsertParameter ( command, parameterName, 
                            column.ColumnName, 
                            row [ column.ColumnName ] );
        }
      }
      return command;
    }

    // Inserts the DataRow for the connection, returning the identity
    public static object InsertDataRow ( DataRow row, string connectionString )
    {
      SqlCommand command = CreateInsertCommand ( row );

      using ( SqlConnection connection = new SqlConnection ( connectionString ) )
      {
        command.Connection = connection;
        command.CommandType = System.Data.CommandType.Text;
        connection.Open ();
        return command.ExecuteScalar ();
      }
    }

  }
}

Using the Code

Just include the source file in your program and call the functions. The (extremely basic) sample program uses the Northwind code files, but does not connect to it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ian Semmel
Web Developer
Australia Australia
Member
I have been programming for about 100 years (42 actually) and have just moved in to C# and SQL.
 
My main work nowdays involves MFC, but I do a bit of Linux/Unix stuff in C++.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membergrigorij8913 Sep '12 - 3:53 
Fantastic solution, very helpful for me.
Suggestion1 small changememberleote11 Apr '12 - 1:22 
Hi, had a error with a database with a field named "check", so made a small change on
 
public static string BuildInsertSQL ( DataTable table )
 
changed the
 
sql.Append ( column.ColumnName );
 
to
 
sql.Append ( "[" + column.ColumnName + "]" );
GeneralMy vote of 5membereibbed10 Aug '11 - 15:26 
I was just about to write code to do this exact thing, thank you.
GeneralThanks a lotmemberashu khanna22 Apr '11 - 7:43 
Thanks Ian,
 
It saved me hours. At the moment, I was a bit confused how to generate the scripts programatically but this all, did the trick for me.
Thumbs Up | :thumbsup: Thumbs Up | :thumbsup:
GeneralUnable to use InsertDataRowmemberkellylc20 Sep '07 - 21:26 
Could you provide an example on how to pass a data row to the InsertDataRow function? I obtain a syntax error as following:-
 
Incorrect syntax near '('.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
 
Exception Details: System.Data.SqlClient.SqlException: Incorrect syntax near '('.
 
Source Error:
 

Line 219: command.CommandType = System.Data.CommandType.Text;
Line 220: connection.Open();
Line 221: command.ExecuteScalar ();
Line 222:
Line 223: }

Thanks.
 
Kelly
GeneralRe: Unable to use InsertDataRowmemberIan Semmel25 Sep '07 - 10:16 
I don't really know what the problem is, but there could be something in your schema that is not handles, eg some sort of sql type. You would really have to debug it and look at the generated sql.
 
Perhaps it is the parameter name. You could look at the vb version contributed by Dan Bruton below.
GeneralVisual Basic Version of the Code (included)memberDan_Bruton5 Aug '07 - 15:55 
Thanks for the *very* useful code. I have coverted it from C# to Visual Basic and included it below. I also modified the code to handle field names with spaces in them (when we do not have a choice).
 

'Usage
InsertDataRow(dr,str)
 

 
Imports System.Data.OleDb
Imports System.Data.SqlClient
Imports System.text
 
Public Class SQLTools
 
' Inserts the DataRow for the connection, returning the identity
Public Function InsertDataRow(ByVal row As DataRow, ByVal connectionString As String) As String
Dim command As SqlCommand = CreateInsertCommand(row)
'Dim connection As SqlConnection
Using connection As SqlConnection = New SqlConnection(connectionString)
command.Connection = connection
command.CommandType = System.Data.CommandType.Text
connection.Open()
Return command.ExecuteScalar()
End Using
End Function
 
Public Function BuildAllFieldsSQL(ByVal table As DataTable) As String
Dim sql As String = ""
Dim dc As DataColumn
For Each dc In table.Columns
If (sql.Length > 0) Then sql += ", "
sql += dc.ColumnName
Next
Return sql
End Function
 
' Returns a SQL INSERT command. Assumes autoincrement is identity (optional)
Public Function BuildInsertSQL(ByVal table As DataTable) As String
Dim sql As StringBuilder = New StringBuilder("INSERT INTO " + table.TableName + " (")
Dim values As StringBuilder = New StringBuilder("VALUES (")
Dim bFirst As Boolean = True
Dim bIdentity As Boolean = False
Dim identityType As String = ""
Dim dc As DataColumn
For Each dc In table.Columns
If (dc.AutoIncrement) Then
bIdentity = True
Select Case dc.DataType.Name
Case "Int16"
identityType = "smallint"
Case "SByte"
identityType = "tinyint"
Case "Int64"
identityType = "bigint"
Case "Decimal"
identityType = "decimal"
Case Else
identityType = "int"
End Select
Else
If (bFirst) Then
bFirst = False
Else
sql.Append(", ")
values.Append(", ")
End If
 
sql.Append("[" & dc.ColumnName & "]")
'sql.Append(Replace(dc.ColumnName, " ", ""))
values.Append("@")
'values.Append(dc.ColumnName)
values.Append(Replace(dc.ColumnName, " ", ""))
 
End If
Next
sql.Append(") ")
sql.Append(values.ToString())
sql.Append(")")
 
If (bIdentity) Then
sql.Append("; SELECT CAST(scope_identity() AS ")
sql.Append(identityType)
sql.Append(")")
End If
Return sql.ToString()
End Function
 

' Creates a SqlParameter and adds it to the command
Public Function InsertParameter(ByVal command As SqlCommand, ByVal parameterName As String, ByVal sourceColumn As String, ByVal value As Object) As SqlCommand
Dim parameter As SqlParameter
parameter = New SqlParameter(parameterName, value)
 
parameter.Direction = ParameterDirection.Input
parameter.ParameterName = parameterName
parameter.SourceColumn = sourceColumn
parameter.SourceVersion = DataRowVersion.Current
 
command.Parameters.Add(parameter)
Return command
End Function
 

' Creates a SqlCommand for inserting a DataRow
Public Function CreateInsertCommand(ByVal row As DataRow) As SqlCommand
Dim table As DataTable = row.Table
Dim sql As String = BuildInsertSQL(table)
Dim command As SqlCommand = New SqlCommand(sql)
command.CommandType = System.Data.CommandType.Text
Dim dc As DataColumn
For Each dc In table.Columns
If (Not dc.AutoIncrement) Then
Dim parameterName As String = "@" + Replace(dc.ColumnName, " ", "")
InsertParameter(command, parameterName, dc.ColumnName, row(dc.ColumnName))
End If
next
Return command
End Function
 
End Class

GeneralThank YoumemberLev Vayner.31 Jul '07 - 4:45 
Wink | ;) Ian,
Thank you for the article. This is very useful (as I have used it in my app already Smile | :)
 

Questiondestination field is of a different data typememberkissa4929 Jun '07 - 8:23 
The destination fields in the SQL table that I will be inserting my data into are of all different data types: some are varchar, some are float, some are int. I need to figure out each type and then do a cast on the values im inserting, (they are all saved as strings in my DataTable). How can I figure out, one by one, the data types of the fields so I can do the casting.
Thank you!
 
Vicky
 

-- modified at 15:11 Friday 29th June, 2007
Generalinsert datatable into SQL SERVER table using single querymemberrajnish_haldiya12 Jun '07 - 22:48 
Hi friends,
 
I have a datatable that is holding the data for an Excel sheet records. Now i want to insert all the data of this datatable to a SQL SERVER database table.
 
if ordinarily i do it ,then i would need to open and close the database connection for as many times as many rows in datatable.
 
Is there any way to insert this datatable data to SQL SERVER datatable by a single database insert query.
 
If it is possible , then could anybody provide the code for it.
 
Any help will be greatly appritiated...
Many Many Thanks in advance

 
Rajnish

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 29 Jun 2006
Article Copyright 2006 by Ian Semmel
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid