0

我需要在不使用 OracleBulkCopy(使用托管数据访问)的情况下将表从 MS Access 复制到 Oracle。第一步是创建表。

从下面的代码中可以看出,我现在在查询列长度时手动转换字段。

我想使用一个语句来为我转换字段,而不必手动为所有类型添加规则,因为有很多类型。或者更好的是,只需提取某种我可以在 Oracle 中执行的 DDL。这可能吗?

            private int GetLength(string accessTableName, string columnName, OleDbConnection accessConnection)
            {
                columnName = $"[{columnName}]";
                var accessCommand = new OleDbCommand($"select max(len({columnName})) from {accessTableName}", accessConnection);
                return int.Parse(accessCommand.ExecuteScalar().ToString());
            }

            private void CreateEmptyTable(DataTable schemaTable, string tableName, OracleConnection oracleConnection, string accessTableName, OleDbConnection accessConnection)
            {
                var columnSpecs = new string[schemaTable.Rows.Count];
                for (int i = 0; i < schemaTable.Rows.Count; ++i)
                {
                    var name = schemaTable.Rows[i].ItemArray[0].ToString();
                    var dataType = schemaTable.Rows[i].ItemArray[5];
                    //var length = schemaTable.Rows[i].ItemArray[2];
                    var length = GetLength(accessTableName, name.ToString(), accessConnection);

                    var precision = schemaTable.Rows[i].ItemArray[3];
                    var scale = schemaTable.Rows[i].ItemArray[4];

                    var oracleDt = "";
                    switch (dataType.ToString())
                    {
                        case "System.String":
                            oracleDt = $"nchar({length})";
                            break;
                        case "System.Int32":
                        case "System.Int16":
                            var iLng = int.Parse(length.ToString()) * 2;
                            oracleDt = $"number({iLng},0)";
                            break;
                        case "System.Double":
                        case "System.Decimal":
                            oracleDt = $"number({length},{precision})";
                            break;
                        default:
                            throw new Exception();
                    }

                    name = name.ToString().ToUpper().Replace(' ', '_');

                    columnSpecs[i] = $"{name} {oracleDt}";
                }

                var query = $"create table MDB_{tableName.ToUpper().Replace(' ', '_')} ( {string.Join(",", columnSpecs)} )";

                var oracleCommand = new OracleCommand(query, oracleConnection);
                oracleCommand.ExecuteNonQuery();
            }
4

2 回答 2

1

也许您尝试在基表上执行命令来代替查询。

所以尝试这样的事情:

DoCmd.TransferDatabase acExport, "ODBC Database", strCon,
           acTable, "tblHotels2", "tblHotelEXPORT", True

现在上面来自 Access,但您发布的答案是正确的。

当我将上面的内容发送到 SQL Server 时,long、money、memo、文本文件都被发送出去并在 sql server 上创建。我想你可以使用上面的,然后执行一系列的 alter table 来改变类型,但这会很痛苦。

所以在痛苦的方法之前,我会在上面尝试。请注意:我在基表上使用了传输命令,而不是查询。我使用“True”作为最后一个值——这意味着没有数据复制,只是结构。

您还可以尝试/测试不同的 ORACLE odbc 驱动程序。我没有测试 oracle 服务器,但是将上述内容发送到 SQL 服务器 - 它在服务器端创建数据类型方面做得非常好。

于 2019-03-16T00:30:42.107 回答
0

此选项改用互操作,但结果令人失望。数值字段转为VARCHAR2,其他类型暂未测试。请注意,它还需要 DSN 文件,并且需要 Oracle ODBC 驱动程序。

对于可以使用它的人,这里是代码:

public void CreateTableDefsUsingInterop(string accessFilePath, string accessTable, string oracleUser, string oraclePassword, string oracleTable, string oracleDSNFilePath)
{
    var strConn = $"ODBC;FILEDSN={oracleDSNFilePath};UID={oracleUser};PWD={oraclePassword}";
    var sTypExprt = "ODBC Database";

    var interop = new Application();
    interop.OpenCurrentDatabase(accessFilePath);
    var db = interop.CurrentDb();
    var emptyTable = $"n{accessTable}";
    QueryDef qd;

    qd = db.CreateQueryDef("access2ora1", $"select top 1 * into [{emptyTable}] from [{accessTable}]");
    qd.Execute();

    qd = db.CreateQueryDef("access2ora2", $"delete from [{emptyTable}]");
    qd.Execute();

    interop.DoCmd.TransferDatabase(AcDataTransferType.acExport, sTypExprt, strConn, AcObjectType.acTable, emptyTable, oracleTable);

    interop.Quit(AcQuitOption.acQuitSaveNone);
}
于 2019-03-15T17:53:51.780 回答