在 C# 中将 DataTable 转换为 SQL 的 CREATE TABLE + INSERT 脚本
Posted
技术标签:
【中文标题】在 C# 中将 DataTable 转换为 SQL 的 CREATE TABLE + INSERT 脚本【英文标题】:Converting a DataTable to an CREATE TABLE + INSERT script for SQL in C# 【发布时间】:2011-07-10 18:47:48 【问题描述】:我需要从 DataTable 以及其中的 DATA 生成 TSQL 脚本。 这不是一个单一的插入。除此之外,我也需要创建表(相同的数据表结构)
所以:我有一个填充数据的 DataTable。我想要创建此 DataTable 结构的 TSQL 脚本以及 SQL SERVER 中的数据(CREATE TABLE + INSERT)
提前谢谢你 并且特别感谢 John Saunders 帮助我更正了这个问题。
【问题讨论】:
您使用的是哪个版本的 .NET? DataTable 是相当原始的技术,没有内置的方式来做你想要的。 我使用的是 Framework 3.5 vs 2010 那么您应该查看实体框架,它具有创建数据库模型、创建表然后更新它的能力。 DataTable 已经过时了。 在我的情况下提供了一个数据表,我需要创建一个数据集来获取结构吗?要读取数据表中的每一行,我可以这样做并附加它并插入一串字符串。 For Each iRow as Datarow in dtTable string strSQL = "INSERT INTO TestTable(Col1,Col2) VALUES (" + iRow.item("Col1") + "," + iRow.item("Col1") + ")"; 废话,DataTable 并没有“过时”。实体框架对于很多项目来说都是多余的。 【参考方案1】:看看:Generate SQL INSERT commands programmatically
本质上,代码是循环遍历 DataTable.Columns 集合以生成 INSERT 语句的列列表。然后它循环遍历 DataTable 的值以创建具有值的参数。
【讨论】:
【参考方案2】:首先,我会用这个对象来build your CREATE TABLE command.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace Toolkit
public class SqlTableCreator
#region Instance Variables
private SqlConnection _connection;
public SqlConnection Connection
get return _connection;
set _connection = value;
private SqlTransaction _transaction;
public SqlTransaction Transaction
get return _transaction;
set _transaction = value;
private string _tableName;
public string DestinationTableName
get return _tableName;
set _tableName = value;
#endregion
#region Constructor
public SqlTableCreator()
public SqlTableCreator(SqlConnection connection) : this(connection, null)
public SqlTableCreator(SqlConnection connection, SqlTransaction transaction)
_connection = connection;
_transaction = transaction;
#endregion
#region Instance Methods
public object Create(DataTable schema)
return Create(schema, null);
public object Create(DataTable schema, int numKeys)
int[] primaryKeys = new int[numKeys];
for (int i = 0; i < numKeys; i++)
primaryKeys[i] = i;
return Create(schema, primaryKeys);
public object Create(DataTable schema, int[] primaryKeys)
string sql = GetCreateSQL(_tableName, schema, primaryKeys);
SqlCommand cmd;
if (_transaction != null && _transaction.Connection != null)
cmd = new SqlCommand(sql, _connection, _transaction);
else
cmd = new SqlCommand(sql, _connection);
return cmd.ExecuteNonQuery();
public object CreateFromDataTable(DataTable table)
string sql = GetCreateFromDataTableSQL(_tableName, table);
SqlCommand cmd;
if (_transaction != null && _transaction.Connection != null)
cmd = new SqlCommand(sql, _connection, _transaction);
else
cmd = new SqlCommand(sql, _connection);
return cmd.ExecuteNonQuery();
#endregion
#region Static Methods
public static string GetCreateSQL(string tableName, DataTable schema, int[] primaryKeys)
string sql = "CREATE TABLE [" + tableName + "] (\n";
// columns
foreach (DataRow column in schema.Rows)
if (!(schema.Columns.Contains("IsHidden") && (bool)column["IsHidden"]))
sql += "\t[" + column["ColumnName"].ToString() + "] " + SQLGetType(column);
if (schema.Columns.Contains("AllowDBNull") && (bool)column["AllowDBNull"] == false)
sql += " NOT NULL";
sql += ",\n";
sql = sql.TrimEnd(new char[] ',', '\n' ) + "\n";
// primary keys
string pk = ", CONSTRAINT PK_" + tableName + " PRIMARY KEY CLUSTERED (";
bool hasKeys = (primaryKeys != null && primaryKeys.Length > 0);
if (hasKeys)
// user defined keys
foreach (int key in primaryKeys)
pk += schema.Rows[key]["ColumnName"].ToString() + ", ";
else
// check schema for keys
string keys = string.Join(", ", GetPrimaryKeys(schema));
pk += keys;
hasKeys = keys.Length > 0;
pk = pk.TrimEnd(new char[] ',', ' ', '\n' ) + ")\n";
if (hasKeys) sql += pk;
sql += ")";
return sql;
public static string GetCreateFromDataTableSQL(string tableName, DataTable table)
string sql = "CREATE TABLE [" + tableName + "] (\n";
// columns
foreach (DataColumn column in table.Columns)
sql += "[" + column.ColumnName + "] " + SQLGetType(column) + ",\n";
sql = sql.TrimEnd(new char[] ',', '\n' ) + "\n";
// primary keys
if (table.PrimaryKey.Length > 0)
sql += "CONSTRAINT [PK_" + tableName + "] PRIMARY KEY CLUSTERED (";
foreach (DataColumn column in table.PrimaryKey)
sql += "[" + column.ColumnName + "],";
sql = sql.TrimEnd(new char[] ',' ) + "))\n";
//if not ends with ")"
if ((table.PrimaryKey.Length == 0) && (!sql.EndsWith(")")))
sql += ")";
return sql;
public static string[] GetPrimaryKeys(DataTable schema)
List<string> keys = new List<string>();
foreach (DataRow column in schema.Rows)
if (schema.Columns.Contains("IsKey") && (bool)column["IsKey"])
keys.Add(column["ColumnName"].ToString());
return keys.ToArray();
// Return T-SQL data type definition, based on schema definition for a column
public static string SQLGetType(object type, int columnSize, int numericPrecision, int numericScale)
switch (type.ToString())
case "System.String":
return "VARCHAR(" + ((columnSize == -1) ? "255" : (columnSize > 8000) ? "MAX" : columnSize.ToString() ) + ")";
case "System.Decimal":
if (numericScale > 0)
return "REAL";
else if (numericPrecision > 10)
return "BIGINT";
else
return "INT";
case "System.Double":
case "System.Single":
return "REAL";
case "System.Int64":
return "BIGINT";
case "System.Int16":
case "System.Int32":
return "INT";
case "System.DateTime":
return "DATETIME";
case "System.Boolean":
return "BIT";
case "System.Byte":
return "TINYINT";
case "System.Guid":
return "UNIQUEIDENTIFIER";
default:
throw new Exception(type.ToString() + " not implemented.");
// Overload based on row from schema table
public static string SQLGetType(DataRow schemaRow)
return SQLGetType(schemaRow["DataType"],
int.Parse(schemaRow["ColumnSize"].ToString()),
int.Parse(schemaRow["NumericPrecision"].ToString()),
int.Parse(schemaRow["NumericScale"].ToString()));
// Overload based on DataColumn from DataTable type
public static string SQLGetType(DataColumn column)
return SQLGetType(column.DataType, column.MaxLength, 10, 2);
#endregion
然后我会使用 SQL BulkCopy 而不是单独的 INSERT 语句。
public static void BulkInsertDataTable(string connectionString, string tableName, DataTable table)
using (SqlConnection connection = new SqlConnection(connectionString))
SqlBulkCopy bulkCopy =
new SqlBulkCopy
(
connection,
SqlBulkCopyOptions.TableLock |
SqlBulkCopyOptions.FireTriggers |
SqlBulkCopyOptions.UseInternalTransaction,
null
);
bulkCopy.DestinationTableName = tableName;
connection.Open();
bulkCopy.WriteToServer(table);
connection.Close();
【讨论】:
您的 VARCHAR 缺少结束括号。试试这个 VARCHAR(" + ((table.Columns[i].MaxLength == -1) ? "255), " : (table.Columns[i].MaxLength > 8000) ? "MAX), " : table.Columns [i].MaxLength.ToString() + "), "));【参考方案3】:如果您想从表中创建insert
脚本,请使用我创建的工具。
这会根据给定的条件在多个表上创建 Insert
脚本:
IF NOT EXISTS (Select 1 from Table1 WHERE Col1='Col1' AND Col2='Col2')
INSERT INTO Table1 (Col1,Col2,Col3,Col4) VALUES (1,'abc',null,'2012-01-01')
这里是链接:http://www.codeproject.com/Tips/330864/Generate-Insert-script-to-extract-data
【讨论】:
那篇文章我看了两遍,但不清楚它在做什么。【参考方案4】:public void createsqltable(DataTable dt,string tablename)
string strconnection = "";
string table = "";
table += "IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[" + tablename + "]') AND type in (N'U'))";
table += "BEGIN ";
table += "create table " + tablename + "";
table += "(";
for (int i = 0; i < dt.Columns.Count; i++)
if (i != dt.Columns.Count-1)
table += dt.Columns[i].ColumnName + " " + "varchar(max)" + ",";
else
table += dt.Columns[i].ColumnName + " " + "varchar(max)";
table += ") ";
table += "END";
InsertQuery(table,strconnection);
CopyData(strconnection, dt, tablename);
public void InsertQuery(string qry,string connection)
SqlConnection _connection = new SqlConnection(connection);
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = qry;
cmd.Connection = _connection;
_connection.Open();
cmd.ExecuteNonQuery();
_connection.Close();
public static void CopyData(string connStr, DataTable dt, string tablename)
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(connStr, SqlBulkCopyOptions.TableLock))
bulkCopy.DestinationTableName = tablename;
bulkCopy.WriteToServer(dt);
【讨论】:
我在dt.Columns[i].ColumnName
上添加了花括号,以防止列名包含空格时引发错误以上是关于在 C# 中将 DataTable 转换为 SQL 的 CREATE TABLE + INSERT 脚本的主要内容,如果未能解决你的问题,请参考以下文章
C# 在 .NET 1.1 中将 DataView 转换为表(DataTable)
在 C# 中将数据加载到 DataTable 会出现“未知 SQL 类型 - 0”错误