J'ai importé des données à partir d'un fichier Excel et je les ai enregistrées dans une datatable
. Maintenant, j'aimerais enregistrer cette information dans ma base de données SQL Server
.
J'ai vu beaucoup d'informations sur le web mais je ne peux pas le comprendre:
OLE
ou SQL Server
(comme dataAdapter
ou connection
)?Mon besoin est de lire le rapport hebdomadaire des heures de travail des employés, à partir de son fichier Excel, et de l'enregistrer dans une table de base de données dans laquelle tous les rapports sont enregistrés (mise à jour de la base de données avec de nouveaux enregistrements chaque semaine).
Le fichier Excel contient des rapports uniquement pour la semaine en cours.
Créez un User-Defined TableType
dans votre base de données:
CREATE TYPE [dbo].[MyTableType] AS TABLE(
[Id] int NOT NULL,
[Name] [nvarchar](128) NULL
)
et définissez un paramètre dans votre Stored Procedure
:
CREATE PROCEDURE [dbo].[InsertTable]
@myTableType MyTableType readonly
AS
BEGIN
insert into [dbo].Records select * from @myTableType
END
et envoyez votre DataTable
directement au serveur SQL:
using (var command = new SqlCommand("InsertTable") {CommandType = CommandType.StoredProcedure})
{
var dt = new DataTable(); //create your own data table
command.Parameters.Add(new SqlParameter("@myTableType", dt));
SqlHelper.Exec(command);
}
Pour éditer les valeurs dans une procédure stockée, vous pouvez déclarer une variable locale du même type et y insérer une table d'entrée:
DECLARE @modifiableTableType MyTableType
INSERT INTO @modifiableTableType SELECT * FROM @myTableType
Ensuite, vous pouvez éditer @modifiableTableType
:
UPDATE @modifiableTableType SET [Name] = 'new value'
Si c'est la première fois que vous sauvegardez vos données
Faites ceci (en utilisant une copie en bloc). S'assurer qu'il n'y a pas de contrainte PK/FK
SqlBulkCopy bulkcopy = new SqlBulkCopy(myConnection);
//I assume you have created the table previously
//Someone else here already showed how
bulkcopy.DestinationTableName = table.TableName;
try
{
bulkcopy.WriteToServer(table);
}
catch(Exception e)
{
messagebox.show(e.message);
}
Maintenant que vous avez déjà un enregistrement de base. Et vous voulez juste vérifier le nouvel enregistrement avec celui existant. Vous pouvez simplement faire ceci.
Cela prendra essentiellement la table existante de la base de données
DataTable Table = new DataTable();
SqlConnection Connection = new SqlConnection("ConnectionString");
//I assume you know better what is your connection string
SqlDataAdapter adapter = new SqlDataAdapter("Select * from " + TableName, Connection);
adapter.Fill(Table);
Puis passez cette table à cette fonction
public DataTable CompareDataTables(DataTable first, DataTable second)
{
first.TableName = "FirstTable";
second.TableName = "SecondTable";
DataTable table = new DataTable("Difference");
try
{
using (DataSet ds = new DataSet())
{
ds.Tables.AddRange(new DataTable[] { first.Copy(), second.Copy() });
DataColumn[] firstcolumns = new DataColumn[ds.Tables[0].Columns.Count];
for (int i = 0; i < firstcolumns.Length; i++)
{
firstcolumns[i] = ds.Tables[0].Columns[i];
}
DataColumn[] secondcolumns = new DataColumn[ds.Table[1].Columns.Count];
for (int i = 0; i < secondcolumns.Length; i++)
{
secondcolumns[i] = ds.Tables[1].Columns[i];
}
DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
ds.Relations.Add(r);
for (int i = 0; i < first.Columns.Count; i++)
{
table.Columns.Add(first.Columns[i].ColumnName, first.Columns[i].DataType);
}
table.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r);
if (childrows == null || childrows.Length == 0)
table.LoadDataRow(parentrow.ItemArray, true);
}
table.EndLoadData();
}
}
catch (Exception ex)
{
throw ex;
}
return table;
}
Cela renverra un nouveau DataTable avec les lignes modifiées mises à jour. Veuillez vous assurer que vous appelez la fonction correctement. Le premier DataTable est censé être le dernier.
Répétez ensuite la fonction bulkcopy de nouveau avec ce nouvel élément de données.
Je donne un code très simple, que j'ai utilisé dans ma solution (j'ai le même énoncé de problème que le vôtre)
SqlConnection con = connection string ;
//new SqlConnection("Data Source=.;uid=sa;pwd=sa123;database=Example1");
con.Open();
string sql = "Create Table abcd (";
foreach (DataColumn column in dt.Columns)
{
sql += "[" + column.ColumnName + "] " + "nvarchar(50)" + ",";
}
sql = sql.TrimEnd(new char[] { ',' }) + ")";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.ExecuteNonQuery();
using (var adapter = new SqlDataAdapter("SELECT * FROM abcd", con))
using(var builder = new SqlCommandBuilder(adapter))
{
adapter.InsertCommand = builder.GetInsertCommand();
adapter.Update(dt);
// adapter.Update(ds.Tables[0]); (Incase u have a data-set)
}
con.Close();
J'ai donné un nom de table prédéfini comme "abcd" (vous devez veiller à ce qu'une table portant ce nom n'existe pas dans votre base de données) . Merci de voter ma réponse si cela vous convient !!! :)
Je vous suggère d’insérer une insertion en bloc comme suggéré dans cet article: Insertion en bloc de données à l’aide de C # DataTable et de la fonction OpenXML du serveur SQL
//best way to deal with this is sqlbulkcopy
//but if you dont like it you can do it like this
//read current sql table in an adapter
//add rows of datatable , I have mentioned a simple way of it
//and finally updating changes
Dim cnn As New SqlConnection("connection string")
cnn.Open()
Dim cmd As New SqlCommand("select * from sql_server_table", cnn)
Dim da As New SqlDataAdapter(cmd)
Dim ds As New DataSet()
da.Fill(ds, "sql_server_table")
Dim cb As New SqlCommandBuilder(da)
//for each datatable row
ds.Tables("sql_server_table").Rows.Add(COl1, COl2)
da.Update(ds, "sql_server_table")
public bool BulkCopy(ExcelToSqlBo objExcelToSqlBo, DataTable dt, SqlConnection conn, SqlTransaction tx)
{
int check = 0;
bool result = false;
string getInsert = "";
try
{
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
if (dr != null)
{
if (check == 0)
{
getInsert = "INSERT INTO [tblTemp]([firstName],[lastName],[Father],[Mother],[Category]" +
",[sub_1],[sub_LG2])"+
" select '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString();
check += 1;
}
else
{
getInsert += " UNION ALL ";
getInsert += " select '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString() ;
check++;
}
}
}
result = common.ExecuteNonQuery(getInsert, DatabasesName, conn, tx);
}
else
{
throw new Exception("No row for insertion");
}
dt.Dispose();
}
catch (Exception ex)
{
dt.Dispose();
throw new Exception("Please attach file in Proper format.");
}
return result;
}
J'ai trouvé qu'il était préférable d'ajouter à la table ligne par ligne si votre table a une clé primaire. L'insertion simultanée de l'ensemble du tableau crée un conflit lors de l'incrémentation automatique.
Voici mon Proc stocké
CREATE PROCEDURE dbo.usp_InsertRowsIntoTable
@Year int,
@TeamName nvarchar(50),
AS
INSERT INTO [dbo.TeamOverview]
(Year,TeamName)
VALUES (@Year, @TeamName);
RETURN
Je mets ce code dans une boucle pour chaque ligne que je dois ajouter à ma table:
insertRowbyRowIntoTable(Convert.ToInt16(ddlChooseYear.SelectedValue), name);
Et voici mon code de couche d'accès aux données:
public void insertRowbyRowIntoTable(int ddlValue, string name)
{
SqlConnection cnTemp = null;
string spName = null;
SqlCommand sqlCmdInsert = null;
try
{
cnTemp = helper.GetConnection();
using (SqlConnection connection = cnTemp)
{
if (cnTemp.State != ConnectionState.Open)
cnTemp.Open();
using (sqlCmdInsert = new SqlCommand(spName, cnTemp))
{
spName = "dbo.usp_InsertRowsIntoOverview";
sqlCmdInsert = new SqlCommand(spName, cnTemp);
sqlCmdInsert.CommandType = CommandType.StoredProcedure;
sqlCmdInsert.Parameters.AddWithValue("@Year", ddlValue);
sqlCmdInsert.Parameters.AddWithValue("@TeamName", name);
sqlCmdInsert.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (sqlCmdInsert != null)
sqlCmdInsert.Dispose();
if (cnTemp.State == ConnectionState.Open)
cnTemp.Close();
}
}