Member 14183767 Ответов: 2

Как загрузить файл excel в БД, когда имя листа неизвестно C#


я должен загрузить лист в свою базу данных, но имена листов отличаются, я видел пример того, как загружать, когда имя листа неизвестно (<ahref="https: www.codeproject.com="" articles="" 8096=" "c-retrieve-excel-workbook-sheet-names"="">) Но я не совсем понимаю , как это работает и как включить его в свой код, был бы очень признателен за помощь, так как я все еще новичок(студент) :)

Что я уже пробовал:

public void uploadWBsheet(string excelfile)
    {
        //declare variables - edit these based on your particular situation
        string ssqltable = "[dbo].[UPLOAD_WB]";
        // make sure your sheet name is correct, here sheet name is sheet1, so you can change your sheet name if have different
        string myexceldataquery = "Select * FROM [$] ";
        try
        {
            //create our connection strings
            string sexcelconnectionstring = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + excelfile + ";Extended Properties=" + "\"excel 12.0;hdr=yes;\"";

            SqlConnection sqlconn = new SqlConnection(strConnString);

            sqlconn.Open();
    
            //series of commands to bulk copy data from the excel file into our sql table
            OleDbConnection oledbconn = new OleDbConnection(sexcelconnectionstring);
            OleDbCommand oledbcmd = new OleDbCommand(myexceldataquery, oledbconn);
            oledbconn.Open();
            OleDbDataReader dr = oledbcmd.ExecuteReader();




            SqlBulkCopy bulkcopy = new SqlBulkCopy(strConnString);
            bulkcopy.DestinationTableName = ssqltable;
            //Mapping Table column    

            bulkcopy.ColumnMappings.Add("BeneficiaryID", "[BeneficiaryID]");
            bulkcopy.ColumnMappings.Add("BeneficiaryName", "[BeneficiaryName]");
            bulkcopy.ColumnMappings.Add("BranchNameID", "[BranchNameID]");
            bulkcopy.ColumnMappings.Add("BranchCode", "[BranchCode]");
            bulkcopy.ColumnMappings.Add("AccountType", "[AccountType]");
            bulkcopy.ColumnMappings.Add("AccountNumber", "[AccountNumber]");
            bulkcopy.ColumnMappings.Add("TotalWages", "[TotalWages]");
            bulkcopy.ColumnMappings.Add("PaymentDate", "[PaymentDate]");


            //sqlcmd.ExecuteNonQuery();
            while (dr.Read())
            {
                bulkcopy.WriteToServer(dr);

            }
            oledbconn.Close();
            sqlconn.Close();
        }
        //this.importtotemp();


        catch (Exception) { }
        ClientScript.RegisterStartupScript(GetType(), "alert", "alert('File Uploaded');", true);


    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        string CurrentFilePath = Path.GetFullPath(fuAttachment.PostedFile.FileName);
        uploadWBsheet(CurrentFilePath); 
    }

2 Ответов

Рейтинг:
18

Maciej Los

Если вы хотите получить имя листа, вы должны использовать GetSchema метод:

string sFileName = @"filename";
string sConStr = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;HDR=YES';", sFileName);
DataTable dt = new DataTable();
using (OleDbConnection connection = new OleDbConnection(sConStr))
{
    connection.Open();
    var sheets = connection.GetSchema("TABLES").AsEnumerable()
        .Select(x=>x.Field<string>("TABLE_NAME"))
        .ToList();
    foreach(var sheet in sheets) //loop through the collection of sheets ;)
    {
        //your logic here...
                string myexceldataquery = string.Format("Select * FROM [{0}$]; ", sheet);
                //get data
                using(OleDbCommand oledbcmd = new OleDbCommand(myexceldataquery, oledbconn)
                {
                     oledbconn.Open();
                     using(OleDbDataReader dr = oledbcmd.ExecuteReader())
                     {
                      //sql bulk copy here!
                     }
                }
    }
}


Удачи вам!


Member 14183767

привет , означает ли это, что мне больше не нужна эта строка кода : string myexceldataquery = "Select * FROM [$] ";?

Maciej Los

Нет. Вы должны пройти по кругу через коллекцию листов. Разница в том, что вы уже знаете название листа ;)

Member 14183767

я запутался Мацей, цикл проверяет наличие листа, а затем sqlbulkcopy скопирует все данные с листа в цикле. то есть мне больше не нужно указывать строку myexceldataquery?

Maciej Los

Проверьте обновленный ответ. Я надеюсь, что изменения, которые я внес в код, будут более понятны вам.
Удачи вам!

Member 14183767

Эй, Мацей, спасибо за изменения , я реализовал код вместе с блоком try catch, который он не вставляет, и я даже не получаю ошибку

Maciej Los

И вы думаете, что я могу догадаться, почему это произошло?
Вы должны отладить код и проверить причину странного поведения.

Member 14183767

хорошо спасибо

Member 14183767

Привет , как я могу исправить 'OleDb SqlException: компонент Microsoft Access database engine не может открыть или записать файл Excel. Он уже открыт исключительно другим пользователем, или вам нужно разрешение на просмотр и запись его данных.'

Maciej Los

Запустите Диспетчер задач и закройте все экземпляры MS Excel.

Member 14183767

привет Марсий , мне удалось собрать код вместе , и он работает, проблема в том, что он вставляет записи из листов excel несколько раз, вызывая дублирование записей в моей таблице, как я могу это предотвратить ? как в DataTable? вот фрагмент ниже: string ssqltable = "[dbo].[Апрель]";


пробовать{
string sConStr = строка.Формат("Поставщик=Майкрософт.Туз.Oledb для.12.0;Источник данных={0};расширенные свойства='программы Excel 8.0;HDR съемка=да';", sFileName);
DataTable dt = новый DataTable();
SqlConnection sqlconn = new SqlConnection(strConnString);

sqlconn.Открыть();
using (OleDbConnection connection = new OleDbConnection(sConStr))
{
соединение.Открыть();
dt = соединение.GetOleDbSchemaTable(OleDbSchemaGuid.Таблицы, новый объект[] { null, null, null, "таблица" });
var sheets = dt.Rows[0].Поле<string>("TABLE_NAME");
foreach(var sheet in sheets) //цикл через коллекцию листов ;)
{
//ваша логика здесь...
string myexceldataquery = строка.Формат("Select * FROM [{0}]; ", листы);
//получить данные

OleDbConnection oledbconn = новый OleDbConnection(sConStr);
OleDbCommand oledbcmd = new OleDbCommand(myexceldataquery, oledbconn);
оледбконн.Открыть();


И oledbdatareader др = oledbcmd.Метода executereader();
{
//sql bulk copy здесь!

DataTable table = new DataTable("benlist");
стол.Нагрузка(dr);


//установить путь
строка CurrentFilePath = Path.GetFullPath(fuAttachment.PostedFile.имя файла);


Session["filename"] = Path.GetFileNameWithoutExtension(CurrentFilePath);

SqlBulkCopy bulkcopy = новый SqlBulkCopy(strConnString);
переборка.DestinationTableName = ssqltable;


////Столбец таблицы сопоставления


переборка.ColumnMappings.Добавить("Идентификационный Номер", "[Идентификационный Номер]");
переборка.ColumnMappings.Добавить("дата рождения", "[Добролюбов]");
переборка.ColumnMappings.Add("BranchnameID", "[BranchnameID]");
переборка.ColumnMappings.Add("BranchCode", "[BranchCode]");




переборка.WriteToServer(таблица);

// }
соединение.Закрывать();
sqlconn.Закрывать();

}

}
}


}
catch (исключение){}
ClientScript.RegisterStartupScript(GetType(), "alert", "alert('File Uploaded');", true);

}

Maciej Los

Перед вставкой вы должны проверить, существует ли запись .
Я понятия не имею, как выглядит ваша база данных, и поэтому больше ничем не могу вам помочь.

Member 14183767

могу ли я не проверить datatable, чтобы увидеть, есть ли данные сначала, прежде чем они будут вставлены в базу данных ?

Maciej Los

Нет...

Рейтинг:
0

Vincent Maverick Durano

Я не делал этого раньше, но вы можете попробовать извлечь все имена листов excel, отфильтровать неизвестные имена и затем повторить итерацию к каждому из них перед вызовом bulkcopy.ColumnMappings.Add().

Например (непроверенный и урезанный для простоты):

//rest of your code goes here...

var sheetNames = GetExcelSheetNames("ThePathToYourExcelFileHere");
var unknownNames = sheetNames.Where(o => string.IsNullOrEmpty(o));

SqlBulkCopy bulkcopy = new SqlBulkCopy(strConnString);
            bulkcopy.DestinationTableName = ssqltable;
            //Mapping Table column    

            bulkcopy.ColumnMappings.Add("BeneficiaryID", "[BeneficiaryID]");
            bulkcopy.ColumnMappings.Add("BeneficiaryName", "[BeneficiaryName]");
            bulkcopy.ColumnMappings.Add("BranchNameID", "[BranchNameID]");
            bulkcopy.ColumnMappings.Add("BranchCode", "[BranchCode]");
            bulkcopy.ColumnMappings.Add("AccountType", "[AccountType]");
            bulkcopy.ColumnMappings.Add("AccountNumber", "[AccountNumber]");
            bulkcopy.ColumnMappings.Add("TotalWages", "[TotalWages]");
            bulkcopy.ColumnMappings.Add("PaymentDate", "[PaymentDate]");

            //set default names to unknown names
            for(int i = 1; i <= unknownNames.Length; i++){
                   //map them to database
                   bulkcopy.ColumnMappings.Add("Unknown" + i.ToString(), "[Unknown" + i.ToString() + "]");
            }
               //rest of your code here


То GetExcelSheetNames() метод взят из этой статьи: C# - Получение Имен Листов Книги Excel.[^]


Member 14183767

что я помещаю в эту строку кода: string myexceldataquery = "Select * FROM [$] "; ?

Vincent Maverick Durano

Я думаю, что вам нужно использовать имя листа в вашем запросе Select. Возможно, это поможет: https://www.c-sharpcorner.com/article/import-excel-data-into-sql-table-using-sqlbulkcopy-in-c-sharp/