2016-09-27 38 views
1

我有一个小程序,导入一个csv文件到一个sql服务器数据库 但当你按下按钮两次或东西它会添加重复项。 我需要它,以便在重复时跳过那个。 如果有人可以帮助我的代码,这将是真棒。csv导入sqlserver没有重复使用c#

编辑:我注意到一些说我需要禁用按钮,而它正在工作,而这是一种解决方案,我也希望如果已经有数据库中的东西,它会跳过那部分时,它是在csv文件中与数据库中相同。

代码:

private void button1_Click(object sender, EventArgs e) 
    { 
     SqlConnection con = new SqlConnection(@"server=localhost;Initial Catalog=klantbestand;Integrated Security=SSPI;"); 
      string filepath = @"C:\clients TEST.csv"; 

     StreamReader sr = new StreamReader(filepath); 

     string line = sr.ReadLine(); 
     string[] value = line.Split(';'); 
     DataTable dt = new DataTable(); 
     DataRow row; 

     foreach (string dc in value) 
     { 
      dt.Columns.Add(new DataColumn(dc)); 
     } 

     while (!sr.EndOfStream) 
     { 
      value = sr.ReadLine().Split(';'); 
      if (value.Length == dt.Columns.Count) 
      { 
       row = dt.NewRow(); 
       row.ItemArray = value; 
       dt.Rows.Add(row); 
      } 
     } 

     SqlBulkCopy bc = new SqlBulkCopy(con.ConnectionString, SqlBulkCopyOptions.TableLock); 
     bc.DestinationTableName = "GegevensCSV"; 
     bc.BatchSize = dt.Rows.Count; 
     con.Open(); 
     bc.WriteToServer(dt); 
     bc.Close(); 
     con.Close(); 
    } 
+0

在工作时做出某种互斥或禁用按钮不是更安全的选择吗? – rualmar

+0

好吧,它不只是当你按下按钮两次。这是数据库中已经存在与csv文件中相同的值的时候。 – Stijn

回答

1

@AdaTheDev的答案是正确的。但是有另外一种方法可以做到这一点。

如果在进行批量导入时存在重复插入问题,则还可以使用存储过程而不是使用批量复制功能来处理它。

在SQL Server中,对于晚于2005年的版本,可以使用“表值参数”即,您可以将整个表作为参数传递到存储过程并在服务器端进行操作。

如果通过存储过程参数将表传递给服务器端,那么您可以使用“合并命令”,其中merge命令是一个upsert命令。即您可以插入以及以最安全和最快的方式从相同的命令更新或删除所需的记录。

以下是有关过程的一些细节:

第1步:创建为在SQL Server表值参数;该命令是:

CREATE TYPE [dbo].[TableTypeName] AS TABLE(
    [ColumnName1] [DataType], 
    [ColumnName2] [DataType], 
    [ColumnName3] [DataType] 
) 
GO 

这里“ColumnName1,2,3”是表列的名称和“数据类型”是分配给列中的SQL Server数据类型。

步骤2:与合并命令创建存储过程为:

CREATE PROCEDURE [dbo].[ProcedureName] 

    @TableTypeName [dbo].[TableTypeName] READONLY 

AS 
BEGIN 

    DECLARE @InsertedRowsId TABLE 
    (
     [InsertedRowId] [DataType] NOT NULL 
    ); 
    DELETE FROM @InsertedRowsId; 

    BEGIN TRY 

     BEGIN TRANSACTION 

      -- Merge command 
      MERGE INTO [dbo].[TableName] AS [Target] 
      USING (  
        SELECT * FROM @TableTypeName        
       ) AS [Source] 
      -- Candidate Keys: All the column(s) combination that makes the record(s) unique. 
      ON [Target].[ColumnName1] = [Source].[ColumnName1] -- Always false, ensures all rows copied 
      AND [Target].[ColumnName2] = [Source].[ColumnName2] 
      AND [Target].[ColumnName2] = [Source].[ColumnName2] 

      WHEN NOT MATCHED THEN 
       INSERT 
        (
         [ColumnName1] 
         ,[ColumnName1] 
         ,[ColumnName1] 
        ) 
       VALUES 
        (
         [Source].[ColumnName1] 
         ,[Source].[ColumnName1] 
         ,[Source].[ColumnName1] 
        );   

     COMMIT TRANSACTION 

    END TRY 
    BEGIN CATCH 
     ROLLBACK TRANSACTION 
    END CATCH 

END 

步骤3:现在调用存储过程的最后步骤。

Private void button1_Click(object sender, EventArgs e) 
{ 
    string connectionString = @"server=localhost;Initial Catalog=klantbestand;Integrated Security=SSPI;"; 
    string filepath = @"C:\clients TEST.csv"; 

    StreamReader sr = new StreamReader(filepath); 

    string line = sr.ReadLine(); 
    string[] value = line.Split(';'); 
    DataTable dt = new DataTable(); 
    DataRow row; 

    foreach (string dc in value) 
    { 
     dt.Columns.Add(new DataColumn(dc)); 
    } 

    while (!sr.EndOfStream) 
    { 
     value = sr.ReadLine().Split(';'); 
     if (value.Length == dt.Columns.Count) 
     { 
      row = dt.NewRow(); 
      row.ItemArray = value; 
      dt.Rows.Add(row); 
     } 
    } 

    if (dt.Rows.Count>0) { 
     using (SqlConnection connection = new SqlConnection(connectionString)) { 
     connection.Open(); 
     using (SqlCommand command = connection.CreateCommand()) { 
       command.CommandText = "dbo.ProcedureName"; 
       command.CommandType = CommandType.StoredProcedure; 

       SqlParameter parameter;    
       parameter = command.Parameters.AddWithValue("@TableTypeName", dt);    
       parameter.SqlDbType = SqlDbType.Structured; 
       parameter.TypeName = "dbo.TableTypeName"; 

       command.ExecuteNonQuery(); 
      } 
     } 
    }   
} 

通过这种方式,您可以批量导入数据而不会有任何重复记录。 甚至,如果需要,您可以记录插入或异常详细信息。

+0

所以我尝试了这一点,我得到了exeption System.Data.dll中发生类型'System.Data.SqlClient.SqlException'的未处理的异常 附加信息:字符串或二进制数据将被截断。 表值参数“@TableTypeName”的数据不符合参数的表类型。 SQL Server错误是:8152,状态:10 该语句已被终止。 – Stijn

+0

异常的类型是字符串截断,即为varchar字段定义的大小是不够的。 \t其次,FOR“”@TableTypeName“不符合参数的表格类型”指的是存储过程中定义的参数名称与SqlParameter中设置的参数名称不匹配 –

3

我跟随在批量加载数据到数据库表中是创建一个新的临时表(即只存在暂时进口的持续时间)的一般原则,批量加载所有将数据输入到该数据库中,然后运行查询将该数据迁移到最终的目标表中。之后,只需放下临时表。

这给出了几个好处:

  1. 您可以increase initial bulk loading performance到DB /降低初始竞争,而不会影响使用目标表(例如SqlBulkCopyOptions .TableLock)
  2. 然后,您可以实现的事情其他进程第二个迁移步骤,比如不复制最终目标表中已存在的数据(如您想要的那样)
+0

你能帮我带上一些代码吗?我对编程还不是很了解。 – Stijn