65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ScriptBuilder 轻松创建 INSERT 批处理文件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.19/5 (7投票s)

2009年10月13日

CPOL

4分钟阅读

viewsIcon

35981

downloadIcon

405

用于生成 SQL Server INSERT 脚本的实用程序

ScriptBuilder1.jpg

引言

ScriptBuilder 是一个方便、简单的工具,用于为 SQL Server 数据库 (2000-2008) 生成 INSERT 语句。

背景

程序员和 QA 人员在将应用程序从开发环境迁移到 QA 环境再到生产环境时,经常需要生成脚本。

在许多情况下,禁止使用 SSIS 或 DTS。

ScriptBuilder 为此创建了可移植、安全的 INSERT 语句。

Using the Code

这是一个完整的应用程序。您可以随意使用其中的任何代码部分。

这些类,OutputColumnColumnManagerDBAccess,可以提取出来编译成 DLL,供您的应用程序使用。

功能

连接到服务器

单击“连接”按钮打开连接对话框。

scriptbuilderconnect.jpg

输入服务器名称,然后选择 NT 身份验证或 SQL Server 凭据。

ScriptBuilderLogin.jpg

连接成功后,“数据库”下拉列表将填充。选择要从中生成表列表的数据库。

选择一个表将用列列表填充网格。如果列包含标识规范,则列名称旁边会有一个钥匙图标。

设置搜索条件

WHERE 字段是一个自由文本字段,允许用户输入出现在 WHERE 子句中的任何 T-SQL 语句。允许使用复杂表达式和子查询。

用户可以将列名从网格拖放到 WHERE 部分。

WHERE 关键字的使用是可选的。如果未提供,程序将自动添加。

ScriptBuilderWhere.jpg

选择输出

通过单击“选择”列来选择列。至少必须选中一列。如果选择了标识列,则在输出的顶部和底部会添加 IDENTITY_INSERT 语句。

ScriptBuilderGrid.jpg

“自定义值”字段允许用户覆盖生成 SQL 中的值。有两种自定义值:字面字符串,它们将按原样出现在 VALUES 语句中;以及“在服务器上运行”语句。

通过选中“在服务器上运行”列,当获取数据时,自定义值字段中的语句将由 SQL Server 进行评估。

例如,GETDATE() 函数根据是否选中“在服务器上运行”会执行两种截然不同的操作。

ScriptBuilderCustom.jpg

如果选中,脚本中的数据将是脚本运行的实际日期。VALUES(1243, 'October 3, 2009 09:45:12',...)。如果未选中,GETDATE() 语句将出现在 VALUES 语句中,并将插入脚本运行时生成的实际日期。例如:VALUES(1243,GETDATE(),...

创建脚本文件

最后,选择一个文件并单击“生成脚本”按钮。成功后,将出现一个超链接控件,允许用户查看文件。

幕后细节

列元数据存储在 OutputColumn 类中。每个字段都公开为读/写属性。

OutputColumn::OutputColumn(void)
{
     _colName = String::Empty;
     _isKey = false;
     _colOverride = String::Empty;
     _colType = String::Empty;
}

列集合由用户构建,用户在窗体上选择他们想要的输出字段。每一行都通过 addColumn 方法传递到 ColumnManager 对象。

OutputColumn^ col = gcnew OutputColumn;

col->ColumnName = row["name"]->ToString();
col->ColumnOverride = colOverride;
col->ColumnType = row["data_type"]->ToString();
col->IsKey = Convert::ToBoolean(row["id_col"]);
col->RunAtServer = runAtServer;

_colList->Add(col);

通过动态生成两个 SQL 语句来完成代码生成:一个用于获取要编写脚本的数据的 SQL,以及实际输出的 SQL 脚本。

下面的代码片段生成两个列列表:出现在 INSERT INTO (columns) 中的列,以及列和“在服务器上运行” T-SQL 语句的列表。

例如,“在服务器上运行”自定义语句可能是 LEFT(column_one, 3) GETDATE(),如果您想捕获生成脚本的日期。

...

//Create comma separated list of column names
for (int i = 0; i < _colList->Count; i++) 
{
     sbHeader->Append("[" + _colList[i]->ColumnName + "]" + 
	(i < _colList->Count -1 ? "," : ""));

//Build Select string for data call. User can override column name with 
//a T-SQL statement (or string literal).
if(_colList[i]->RunAtServer && _colList[i]->ColumnOverride != String::Empty)
{
     sbSelCols->Append(_colList[i]->ColumnOverride + 
	(i < _colList->Count -1 ? "," : ""));
}
else
{
	sbSelCols->Append("[" + _colList[i]->ColumnName + "]" + 
		(i < _colList->Count -1 ? "," : ""));
}

...

数据获取是一个简单的动态 SQL 语句,可以包含一个可选的 WHERE 子句。

//Fetch data to be scripted
SqlDataReader^ rdr = _dba->getData("SELECT " + selCols + " FROM " + tableName + " " +
    whereClause);
		
//Build INSERT statement rows
while(rdr->Read())
{
			
     sbGetData->Append(insertHeader);
     sbGetData->Append("VALUES(");

...

应用程序遍历返回的 SQLDataReader 并完成 VALUES(data values) 语句。未设置为“在服务器上运行”的自定义覆盖会简单地替换返回的值。如果您想让创建的日期列使用当前日期时间进行填充,这会很有用。您可以使用 GETDATE() 函数来完成此操作。也许您想用 'migration_user' 之类的东西覆盖原始的最后更新用户。

for(int i = 0; i < rdr->FieldCount; i++)
{			
    //If there is no column override or there is one but it's set to RunAtServer
    //put in the value returned in the DataTable
    if(_colList[i]->ColumnOverride->Equals(String::Empty) ||
          _colList[i]->RunAtServer)
    {				 
					
	if(rdr[i]->GetType() == String::typeid ||
		rdr[i]->GetType() == DateTime::typeid) 
	{
		fieldData = rdr[i]->ToString();
		//check for escaping quotes
		fieldData = escapeText(fieldData);

		sbGetData->Append("'" + fieldData + "'" + 
			(i < _colList->Count -1 ? "," : ""));
						
	}
	else if (rdr[i]->GetType() ==  DBNull::typeid)
	{
		sbGetData->Append("NULL" + (i < _colList->Count -1 ? "," : ""));
	}
	else if (rdr[i]->GetType() == Boolean::typeid)
	{						
            sbGetData->Append(Convert::ToInt32(rdr->GetBoolean(i)).ToString() + 
		(i < _colList->Count -1 ? "," : ""));
	}
	else
	{
	    fieldData = rdr[i]->ToString();
	    //check for escaping quotes
	    fieldData = escapeText(fieldData);

	    sbGetData->Append(fieldData + 
		(i < _colList->Count -1 ? "," : ""));
	}

     }	
     else //Using a column override value
     {
	sbGetData->Append(_colList[i]->ColumnOverride + 
		(i < _colList->Count -1 ? "," : ""));
     }

}
...

生成的 string 被写入用户指定的、扩展名为 .sql 的文件。

关注点

很酷的功能包括

  • 能够编写覆盖表中值的自定义表达式。
  • “在服务器上运行”自定义表达式,可在生成数据时评估 T-SQL 语句。
  • 如果找到标识列,自动生成 IDENTITY_INSERT 语句。

其他高级功能包括能够将字段名从列网格拖放到 WHERE 子句文本框,以及自定义列,允许您用字面字符串或任何 T-SQL 函数(例如 GETDATE())覆盖任何列值。

注意,处理大型数据集时可能会非常慢。

历史

  • 2009 年 10 月 13 日:初次发布
  • 2009 年 12 月 7 日:更新了源代码文件 - 小错误修复
© . All rights reserved.