问题:普遍的 odbc 驱动程序((称为:“普遍的 ODBC 引擎接口”)在 ODBC(odbcad32.exe) 中可见。但是,相同的 odbc 驱动程序在 SQL Server 2008 导入向导中不可见,尽管我可以看到相同的 odbc 驱动程序在 SQL Server 2000 导入向导中。
我正在使用带有 SQL server 2008、SQL server 2000 和普遍 SQL v11 的 32 位 win 7 操作系统。任何解决方案都会非常有帮助......非常感谢!
问题:普遍的 odbc 驱动程序((称为:“普遍的 ODBC 引擎接口”)在 ODBC(odbcad32.exe) 中可见。但是,相同的 odbc 驱动程序在 SQL Server 2008 导入向导中不可见,尽管我可以看到相同的 odbc 驱动程序在 SQL Server 2000 导入向导中。
我正在使用带有 SQL server 2008、SQL server 2000 和普遍 SQL v11 的 32 位 win 7 操作系统。任何解决方案都会非常有帮助......非常感谢!
我永远无法弄清楚如何使“导入/导出”向导在 Sql Server Management Studio 中工作。正如我在另一个响应中看到的那样,我什至尝试修改“ProviderResources.xml”文件。
我试图迁移使用专有的“Timberline Data”ODBC 驱动程序的 Sage Timberline Office 数据。当您在 .NET 中调用“GetSchema”函数时,该驱动程序缺少“ORDINAL_POSITION”列。因此 Sql Server Management Studio 中的“导入/导出”失败。
我最终不得不编写自己的应用程序来将数据复制到 SQL 服务器。唯一的缺点是它不知道主键、索引或其他约束。尽管如此,我还是在 MSSQL 中获得了数据,所以我很高兴。
我相信这段代码对其他人有用,所以你去吧。
程序.cs
using System;
using System.Data.Odbc;
using System.Data.SqlClient;
using System.Data;
using System.Collections.Generic;
using System.Diagnostics;
namespace TimberlineOdbcSync
{
class Program
{
static string currentTableName;
const string sourceOdbcDriver = "{Timberline Data}";
const string sourceOdbcDsn = "timberline data source";
const string sourceOdbcUid = "user1";
const string sourceOdbcPwd = "user1a";
const string destSqlServer = "SERVER5";
const string destSqlDatabase = "TSData";
const string destSqlUsername = "";
const string destSqlPassword = "";
const string destSqlOwner = "dbo";
public static void Main(string[] args)
{
DateTime allStartDate = DateTime.Now;
DateTime allEndDate;
DateTime tableStartDate = DateTime.Now;
DateTime tableEndDate;
TimeSpan diff;
string errMsg;
int pCount; //pervasive record count
int sCount; //sql server record count
string sourceOdbcConnString =
"Dsn=" + sourceOdbcDsn + ";" +
"Driver="+ sourceOdbcDriver +";" +
(!string.IsNullOrEmpty(sourceOdbcUid) ? "uid="+ sourceOdbcUid +";" : "") +
(!string.IsNullOrEmpty(sourceOdbcUid) ? "pwd="+ sourceOdbcPwd +";" : "");
string destSqlConnString =
"Server=" + destSqlServer + ";" +
"Database=" + destSqlDatabase+ ";" +
(!string.IsNullOrEmpty(destSqlUsername) && !string.IsNullOrEmpty(destSqlPassword) ?
"User Id=" + destSqlUsername + ";" +
"Password=" + destSqlPassword + ";"
:
"Trusted_Connection=true;");
try{
using(OdbcConnection pConn = new OdbcConnection(sourceOdbcConnString)){
pConn.Open();
List<string> tables = new List<string>();
//get a list of all tables
using(DataTable tableschema = pConn.GetSchema("TABLES"))
foreach(DataRow row in tableschema.Rows)
tables.Add(row["TABLE_NAME"].ToString());
foreach(string tableName in tables){
//set the current table name
currentTableName = tableName;
try{
//get the schema info for the table (from pervasive)
DataTable dtSchema = pConn.GetSchema("Columns", new string[]{null, null, tableName});
//if we could not get the schema
if(dtSchema == null || dtSchema.Rows.Count <= 0){
pConn.Close();
errMsg = "Error: Could not get column information for table " + tableName;
Trace.WriteLine(errMsg);
WriteErrorEvent(errMsg);
return;
}
//emit the table name
Trace.Write("[" + tableName + "]");
//get the number of records in this table
pCount = TableCount(tableName, pConn);
//emit the number of records in this table
Trace.Write(" = P:" + pCount);
//create a data reader to read the pervasive data
string sql = "select * from \""+ tableName + "\"";
OdbcCommand cmd = new OdbcCommand(sql, pConn);
OdbcDataReader dr = cmd.ExecuteReader();
//create a connection to SQL Server
using (SqlConnection sConn = new SqlConnection(destSqlConnString)){
//open the connection
sConn.Open();
//if the table already exists
if(TableExists(tableName, sConn)){
//get the record count for this table
sCount = TableCount(tableName, sConn);
} else {
//set the record count to zero
sCount = 0;
}
//output the record count
Trace.Write(", S: " + sCount);
//if the record counts match
if( pCount == sCount ){
//output an indicator that we are skipping this table
Trace.WriteLine(" -- Skipping");
//skip this table and go to the next
continue;
}
//output a blank line
Trace.WriteLine("");
//create the table in SQL Server using the schema info from Pervasive
CreateTableInDatabase(dtSchema, destSqlOwner, tableName, sConn);
// Copies all rows to the database from the data reader.
using (SqlBulkCopy bc = new SqlBulkCopy(sConn))
{
// Destination table with owner -
// this example does not check the owner names! It uses dbo exclusively.
bc.DestinationTableName = "[" + destSqlOwner + "].[" + tableName + "]";
bc.BulkCopyTimeout = 30;
bc.BatchSize = 3000;
bc.BulkCopyTimeout = 12000;
// User notification with the SqlRowsCopied event
bc.NotifyAfter = 1000;
bc.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnSqlRowsCopied);
//output the date and time so we know when we started
tableStartDate = DateTime.Now;
Trace.WriteLine("Copying " + pCount + " records to " + destSqlServer + " - " + tableStartDate.ToString("g"));
// Starts the bulk copy.
bc.WriteToServer(dr);
tableEndDate = DateTime.Now;
diff = tableEndDate - tableStartDate;
Trace.WriteLine(String.Format(
"Completed {4} at {0}\r\nDuration: {1}:{2}:{3}",
tableEndDate.ToString("g"),
diff.Hours.ToString(), diff.Minutes.ToString(), diff.Seconds.ToString(),
tableName));
// Closes the SqlBulkCopy instance
bc.Close();
}
dr.Close();
}
}catch(Exception ex){
errMsg = "Error: " + ex.Message + Environment.NewLine +
"Stack: " + ex.StackTrace + Environment.NewLine;
Trace.WriteLine(errMsg);
WriteErrorEvent(errMsg);
if( !ReadBool("Do you want to continue? [y/n]") ){
break;
}
}//end try
}//end for
}//end using
allEndDate = DateTime.Now;
diff = allEndDate - allStartDate;
Trace.WriteLine(
"Bulk copy operation complete" + Environment.NewLine +
"Started: " + allStartDate.ToString("g") + Environment.NewLine +
"Current: " + allEndDate.ToString("g") + Environment.NewLine +
String.Format("Duration: {0}:{1}:{2}",
diff.Hours.ToString(),
diff.Minutes.ToString(),
diff.Seconds.ToString()));
}catch(Exception ex){
errMsg =
"Error: " + ex.Message + Environment.NewLine +
"Stack: " + ex.StackTrace;
Trace.WriteLine(errMsg);
WriteErrorEvent(errMsg);
}//end try
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
static bool TableExists(string tableName, SqlConnection sqlConn){
int retVal = 0;
try{
using(SqlCommand command = sqlConn.CreateCommand()){
command.CommandText = "IF OBJECT_ID('dbo." + tableName + "', 'U') IS NOT NULL SELECT 1 as res ELSE SELECT 0 as res";
retVal = Convert.ToInt32(command.ExecuteScalar());
}
}catch(Exception ex){
string errMsg =
"Error: Could not determine if table " + tableName + " exists."+ Environment.NewLine +
"Reason: " + ex.Message + Environment.NewLine +
"Stack: " + ex.StackTrace;
Trace.WriteLine(errMsg);
WriteErrorEvent(errMsg);
retVal = 0;
}//end try
return (retVal==1);
}
static int TableCount(string tableName, IDbConnection anyConn){
int retVal = 0;
try{
using(IDbCommand command = anyConn.CreateCommand()){
command.CommandText = "SELECT count(*) FROM \"" + tableName + "\"";
retVal = Convert.ToInt32(command.ExecuteScalar());
}
}catch(Exception ex){
string errMsg =
"Error: Could not get table count for " + tableName + "." + Environment.NewLine +
"Reason: " + ex.Message + Environment.NewLine +
"Stack: " + ex.StackTrace;
Trace.WriteLine(errMsg);
WriteErrorEvent(errMsg);
retVal = 0;
}//end try
return (retVal);
}
static bool ReadBool(String question) {
while (true) {
Console.WriteLine(question);
String r = (Console.ReadLine() ?? "").ToLower();
if (r == "y" || r == "yes" || r == "1")
return true;
if (r == "n" || r == "no" || r=="0")
return false;
Console.WriteLine("Please Select a Valid Option!!");
}//end while
}
static void OnSqlRowsCopied(object sender, SqlRowsCopiedEventArgs e) {
Trace.WriteLine(String.Format("-- [{1}] Copied {0} rows.", e.RowsCopied, currentTableName));
}
private static string s(object o){
return (Convert.IsDBNull(o) ? "" : Convert.ToString(o));
}
private static string _drToColSql(DataRow dr){
string colName = s(dr["COLUMN_NAME"]);
string ret = "[" + colName + "] ";
string typeName = ((string)s(dr["TYPE_NAME"])).ToLower();
switch(typeName){
case "char":
ret += "CHAR(" + s(dr["LENGTH"]) + ")";
break;
case "byte":
ret += "CHAR(" + s(dr["PRECISION"]) + ")";
break;
case "text":
ret += "VARCHAR(" + s(dr["PRECISION"]) + ")";
break;
case "date":
ret += "DATE";
break;
case "time":
ret += "TIME(7)";
break;
case "double":
ret += "DECIMAL(16,2)"; // + c(dr["PRECISION"]) + "," + c(dr["LENGTH"]) + ")";
break;
case "usmallint":
case "smallint":
ret += "SMALLINT";
break;
case "utinyint":
case "tinyint":
ret += "TINYINT";
break;
case "identity":
case "integer":
ret += "BIGINT";
break;
case "smallidentity":
case "short":
ret += "INT";
break;
case "longvarchar":
case "memo":
ret += "TEXT";
break;
case "checkbox":
ret += "BIT";
break;
case "real":
ret += "REAL";
break;
default:
//this was an unexpected column, figure out what happened
Trace.WriteLine("ERROR - Column '" + colName + "' Details: ");
Trace.WriteLine("\tCOLUMN_NAME: " + s(dr["COLUMN_NAME"]));
Trace.WriteLine("\tTYPE_NAME: " + s(dr["TYPE_NAME"]));
Trace.WriteLine("\tDATA_TYPE: " + s(dr["DATA_TYPE"]));
Trace.WriteLine("\tLENGTH: " + s(dr["LENGTH"]));
Trace.WriteLine("\tPRECISION: " + s(dr["PRECISION"]));
Trace.WriteLine("\tSCALE: " + s(dr["SCALE"]));
Trace.WriteLine("\tNULLABLE: " + s(dr["NULLABLE"]));
throw new Exception("Unexpected data type: " + typeName);
}
if(s(dr["NULLABLE"])=="1"){
ret += " NULL";
}
return ret;
}
private static bool CreateTableInDatabase(DataTable dtSchemaTable, string tableOwner, string tableName, SqlConnection sqlConn) {
// Generates the create table command.
string ctStr = "CREATE TABLE [" + tableOwner + "].[" + tableName + "](\r\n";
for (int i = 0; i < dtSchemaTable.Rows.Count; i++)
{
ctStr += _drToColSql(dtSchemaTable.Rows[i]);
if (i < dtSchemaTable.Rows.Count)
ctStr += ",";
ctStr += "\r\n";
}
ctStr += ")";
// Emit SQL statement
Trace.WriteLine("-".PadLeft(30, '-'));
Trace.WriteLine(ctStr + Environment.NewLine);
// Runs the SQL command to make the destination table.
using(SqlCommand command = sqlConn.CreateCommand()){
command.CommandText = "IF OBJECT_ID('dbo." + tableName + "', 'U') IS NOT NULL DROP TABLE dbo." + tableName;
command.ExecuteNonQuery();
command.CommandText = ctStr;
command.ExecuteNonQuery();
}
return true;
}
private static bool WriteErrorEvent(string errMsg){
const string sSource = "PervasiveOdbcSync";
const string sLog = "Application";
try{
if (!EventLog.SourceExists(sSource))
EventLog.CreateEventSource(sSource,sLog);
EventLog.WriteEntry(sSource, errMsg);
EventLog.WriteEntry(sSource, errMsg, EventLogEntryType.Error, 128);
return true;
}catch(Exception ex){
Trace.WriteLine("Unable to write error to event log. Reason: " + ex.Message);
return false;
}
}
}
}
您需要将 System.Diagnostics.ConsoleTraceListener 添加到 app.config 文件中。这样您就可以看到正在输出的所有内容。如果您还添加了 System.Diagnostics.TextWriterTraceListener,您可以使应用程序也将所有内容输出到日志文件。
在我也安装了 SQL Server 2008 R2 的 PSQL v11 机器上,我没有在 SQL Server 导入和导出向导的“数据源”对话框中看到“普遍的 ODBC 引擎接口”。我确实看到了“Pervasive PSQL OLEDB Provider”和“Pervasive Provider, release v4.0”(以及 3.5 和 3.2)。The Pervasive Provider 是一个 ADO.NET 提供程序。我确实看到了“.Net Framework Data Provider for ODBC”,如果我为 Pervasive DSN(如 DEMODATA)输入了 DSN 名称,它就可以工作。