Мне нужно написать файл Access 97 .mdb

Мне нужно экспортировать данные из базы данных SQL Server 2005 в файл Access 97 .mdb. Клиент, которому это нужно, должен быть Access 97, потому что системе, в которую они импортируют, требуется формат файла Access 97 (не начинайте меня). Любые предложения, как написать старый файл Access из SQL или.Net (или VB6 или Ruby или Python..)?

Заранее спасибо Ли

6 ответов

Решение

Что вам нужно сделать, так это экспортировать в файл Access любую версию Access, которую вы установили (если это 2000...2003; Access 2007 не может записывать в файлы Access 97). Я полагаю, вы уже знаете, как это сделать.

Затем вы можете создать объект Access через COM и попросить его преобразовать ваш новый файл.mdb в новую базу данных Access 97. В VBScript код выглядит следующим образом (при необходимости измените его, если вы используете VBA, VB.Net или другой язык):

const acFileFormatAccess97 = 8

dim app
set app = CreateObject("Access.Application")
app.ConvertAccessProject "y:\mydatabase.mdb", "y:\mydatabase97.mdb", acFileFormatAccess97

Если у вас установлен Access 97, приведенная выше команда не будет работать, потому что в Access не было функции ConvertAccessProject в этой версии. Конечно, вам не нужно конвертировать файл в этом случае в любом случае.

Я бы позволил Sql 2005 сделать это за тебя.

В Sql Management Stuidio щелкните правой кнопкой мыши исходную базу данных, затем "Задачи", затем "Экспорт данных". Вы можете использовать это для экспорта непосредственно в базу данных Access, просто следуйте инструкциям. Или вы можете вывести его в формат файла, который вы можете использовать для доступа в Access.

Лучший способ сделать это через PInvoke. Вам нужно будет передать CREATE_DBV3 параметр для SqlConfigDataSource (). Вот код, взятый из JetSqlUtil.cs моего проекта OSS PlaneDisaster.NET:

    #region PInvoke
    private enum ODBC_Constants : int {
        ODBC_ADD_DSN = 1,
        ODBC_CONFIG_DSN,
        ODBC_REMOVE_DSN,
        ODBC_ADD_SYS_DSN,
        ODBC_CONFIG_SYS_DSN,
        ODBC_REMOVE_SYS_DSN,
        ODBC_REMOVE_DEFAULT_DSN,
    }

    private enum SQL_RETURN_CODE : int
    {
        SQL_ERROR = -1,
        SQL_INVALID_HANDLE = -2,
        SQL_SUCCESS = 0,
        SQL_SUCCESS_WITH_INFO = 1,
        SQL_STILL_EXECUTING = 2,
        SQL_NEED_DATA = 99,
        SQL_NO_DATA = 100
    }

    [DllImport("ODBCCP32.DLL",CharSet=CharSet.Unicode, SetLastError=true)]
    private static extern int SQLConfigDataSource (int hwndParent, ODBC_Constants fRequest, string lpszDriver, string lpszAttributes);

    [DllImport("ODBCCP32.DLL", CharSet = CharSet.Auto)]
    private static extern SQL_RETURN_CODE SQLInstallerError(int iError, ref int pfErrorCode, StringBuilder lpszErrorMsg, int cbErrorMsgMax, ref int pcbErrorMsg);
    #endregion


    internal static string GetOdbcProviderName()
    {
        if (string.IsNullOrEmpty(OdbcProviderName))
        {
            var odbcRegKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\ODBC\\ODBCINST.INI\\ODBC Drivers", false);
            var drivers = new List<string>(odbcRegKey.GetValueNames());
            if (drivers.Contains("Microsoft Access Driver (*.mdb, *.accdb)"))
            {
                OdbcProviderName = "Microsoft Access Driver (*.mdb, *.accdb)";
            }
            else if (drivers.Contains("Microsoft Access Driver (*.mdb)"))
            {
                OdbcProviderName = "Microsoft Access Driver (*.mdb)";
            }
            else
            {
                //TODO: Condider checking for 32 versus 64 bit.
                //TODO: Find a better exception type. http://stackru.com/questions/7221703/what-is-the-proper-exception-to-throw-if-an-odbc-driver-cannot-be-found
                throw new InvalidOperationException("Cannot find an ODBC driver for Microsoft Access. Please download the Microsoft Access Database Engine 2010 Redistributable. http://www.microsoft.com/download/en/details.aspx?id=13255");
            }
        }



    /// <summary>
    /// Creates an Access 2003 database. If the filename specified exists it is 
    /// overwritten.
    /// </summary>
    /// <param name="fileName">The name of the databse to create.</param>
    /// <param name="version">The version of the database to create.</param>
    public static void CreateMDB (string fileName, AccessDbVersion version = AccessDbVersion.Access2003) {
        ;
        if (File.Exists(fileName)) {
            File.Delete(fileName);
        }

        string command = "";
        switch (version)
        {
            case AccessDbVersion.Access95:
                command = "CREATE_DBV3";
                break;
            case AccessDbVersion.Access2000:
                command = "CREATE_DBV4";
                break;
            case AccessDbVersion.Access2003:
                command = "CREATE_DB";
                break;
        }

        string attributes = String.Format("{0}=\"{1}\" General\0", command, fileName);
        int retCode = SQLConfigDataSource 
            (0, ODBC_Constants.ODBC_ADD_DSN,
             GetOdbcProviderName(), attributes);
        if (retCode == 0)
        {
            int errorCode = 0 ;
            int  resizeErrorMesg = 0 ;
            var sbError = new StringBuilder(512);
            SQLInstallerError(1, ref errorCode, sbError, sbError.MaxCapacity, ref resizeErrorMesg);
            throw new ApplicationException(string.Format("Cannot create file: {0}. Error: {1}", fileName, sbError));
        }
    }

Если вам нужно сделать это с 64-разрядной версии SQL-сервера, вам потребуется 64-разрядная версия Office 2010 или установленный распространяемый компонент Microsoft Access Database Engine 2010.

Это большой вопрос! Я на самом деле хотел иметь возможность делать такие вещи программным способом, но в прошлом у меня не было ничего, кроме проблем с этим. Тем не менее, с годами я немного повзрослел в своих навыках.NET, и я подумал, что смогу написать решение, которое можно было бы выполнить как консольное приложение. Это может быть реализовано в виде запланированной задачи на сервере Windows или SQL Server (с использованием агента Sql Server). Я не понимаю, почему это не может быть автоматизировано с сервера Sql без следующего кода, но я действительно получил удовольствие от этого, поэтому мне просто нужно выложить его там. Таблица в Sql и Access - это список собак с идентификатором, именем, породой и окрасом. Общие вещи. Это на самом деле работает на моем рабочем столе между локальным экземпляром Sql Server и Access (2007, но я не знаю, почему это не будет работать с 97). Пожалуйста, не стесняйтесь критиковать.

Кстати, имеет следующее:

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

Вот:

static void Main(string[] args)
{
    SqlConnectionStringBuilder cstrbuilder = new SqlConnectionStringBuilder();
    cstrbuilder.DataSource = "localhost";
    cstrbuilder.UserID = "frogmorton";
    cstrbuilder.Password = "lillypad99";
    cstrbuilder.InitialCatalog = "Dogs";
    SqlConnection sconn = new SqlConnection(cstrbuilder.ToString());
    sconn.Open();
    SqlCommand scmd = new SqlCommand("select * from Dogs", sconn);

    SqlDataReader reader = scmd.ExecuteReader();

    if (reader.HasRows)
    {

        OleDbConnectionStringBuilder sb = new OleDbConnectionStringBuilder();
        sb.Provider = "Microsoft.Jet.OLEDB.4.0";
        sb.PersistSecurityInfo = false;
        sb.DataSource = @"C:\A\StackOverflog\DogBase.mdb";
        OleDbConnection conn = new OleDbConnection(sb.ToString());
        conn.Open();
        OleDbCommand cmd = new OleDbCommand("Delete from Dogs", conn);
        cmd.CommandType = CommandType.Text;
        cmd.ExecuteNonQuery();
        conn.Close();

        OleDbConnection conn2 = new OleDbConnection(sb.ToString());
        conn2.Open();
        OleDbCommand icmd = new OleDbCommand("Insert into dogs (DogID, DogName, Breed, Color) values ({0}, '{1}', '{2}', '{3}');", conn2);
        icmd.CommandType = CommandType.Text;

        while (reader.Read())
        {
            string insertCommandString =
                String.Format("Insert into dogs (DogID, DogName, Breed, Color) values ({0}, '{1}', '{2}', '{3}');"
                , reader.GetInt32(0)
                , reader.GetString(1)
                , reader.GetString(2)
                , reader.GetString(3)
                );
            icmd.CommandText = insertCommandString;
            icmd.ExecuteNonQuery();

        }
        conn2.Close();
    }

    sconn.Close();
}

Это может дать вам отправную точку. И эта статья немного старая, но вы можете кое-что поднять. Я могу найти только те, кто использует Jet 4.0, который совместим с Access 2000, как в предыдущей статье. Использование драйвера MS Access может дать вам то, что вы хотите.

После того, как вы создали базу данных, используйте обычные вещи, связанные с ODBC / OLE DB, в ADO.NET, чтобы создать свою таблицу и заполнить их данными.

Я думаю, что это безумие делать это из SQL Server. Просто создайте ODBC DSN для своего SQL Server, импортируйте таблицы в MDB Access 97 и покончите с этим. Единственная причина, по которой вы могли бы сделать это иначе, - это если вы хотите автоматизировать это и делать это многократно, но это может быть автоматизировано и в Access (TransferDatabase может выполнять импорт ODBC), и будет занимать столько же строк кода, сколько имеется это таблицы для импорта.

Другие вопросы по тегам