基于3个字段的具有重复行的SQL UPSERT查询(C#VisStudio)

时间:2020-09-23 20:02:48

标签: c# sql sql-server sql-update sql-insert

背景是我正在建立一个SQL连接,该连接需要一个.csv文件并将其导入到SQL Server数据库表中。

我遇到的问题是,我在查询语法时遇到问题,因为要导入的.csv文件中的行没有唯一标识符。它需要3个字段的组合才能使一行唯一/不同。

.csv文件数据的粗略示例,.csv列的前三个可以一起考虑以构成唯一的行:

Order_Id  Product_Id  Date    Other (etc...)
    1         1a       1/9      q
    1         2a       1/9      q
    1         2a       1/10     e
    2         1a       1/9      e
    2         2a       1/10     e

这是我在Visual Studios中简化的查询语法,(我实际上是从.csv文件导入25个左右的列,因此为了使事情简单明了,我使两个列的名称完全相同。 csv文件和SQL-Server表),但基本语法如下:

private void SaveImportDataToDatabase(DataTable importData)
{
    using (SqlConnection conn = new SqlConnection("Server=localhost;Database=my_Database;Trusted_Connection=True;"))
    {
        conn.Open();
        foreach (DataRow importRow in importData.Rows)
        {
            
            SqlCommand cmd = new SqlCommand("IF EXISTS(SELECT DISTINCT Order_id, Product_Id, Date FROM Sales WHERE Order_id = @Order_id AND Product_Id = @Product_Id AND Date = @Date) UPDATE SQL_Sales SET Order_id = @Order_id WHERE Order_id = @Order_id ELSE INSERT INTO SQL_Sales (order_id, Product_Id, Date)" +
                                            "VALUES (@order_id, @Product_Id, @Date);", conn);
            
            cmd.Parameters.AddWithValue("@Order_id", importRow["Order_id"]);
            cmd.Parameters.AddWithValue("@Product_Id", importRow["Product_Id"]);
            cmd.Parameters.AddWithValue("@Date", importRow["Date"]);
            
            cmd.ExecuteNonQuery();

        }
    }
}

导入后,我会在SQL Server表中看到一些问题,

  1. order_id字段为空
  2. 它仅导入非常少量的数据,约2000条记录中的50条
  3. 如果我通过.csv文件中的更改重新导入数据(例如,用一个新行),我将获得100条记录(共2000条记录)

我不确定我想做的事是否可行或值得。我是否应该将其分解得更多,而不是在一个查询中全部完成?我不一定是编码新手,但我并不经常编码/我很生疏,这是我的第一个C#项目,因此请耐心等待。

只是想添加更多代码以响应@casey crookston,可能问题2和3与我的循环有关

private void btnImport_Click(object sender, EventArgs e)
    {
       Cursor = Cursors.WaitCursor;            
       DataTable importData = GetDataFromFile();

        if (importData == null) return;
        SaveImportDataToDatabase(importData);

        MessageBox.Show("Import Successful");
        txtFileName.Text = string.Empty;

        Cursor = Cursors.Default;
    }

    private DataTable GetDataFromFile()
    {
        DataTable importedData = new DataTable();
       try
        {
            using (StreamReader sr = new StreamReader(txtFileName.Text))
            {
                string header = sr.ReadLine();
                if (string.IsNullOrEmpty(header))
                {
                    MessageBox.Show("No File Data");
                    return null;
                }

                string[] headerColumns = header.Split(',');
                foreach (string headerColumn in headerColumns)
                {
                    importedData.Columns.Add(headerColumn);
                }

                while (!sr.EndOfStream)
                {
                    string line = sr.ReadLine();

                    if (string.IsNullOrEmpty(line)) continue;

                    string[] fields = line.Split(',');
                    DataRow importedRow = importedData.NewRow();

                    for(int i = 1; i < fields.Count(); i++)
                    {
                        importedRow[i] = fields[i];
                    }

                    importedData.Rows.Add(importedRow);
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("The file could not be read:");
            Console.WriteLine(e.Message);
        }

        return importedData;
    }

1 个答案:

答案 0 :(得分:3)

这似乎是使用SQL Server的MERGE语法的好地方:

merge sales s
using (values(@product_id, @order_id, @date, @other_1, @other_2)) 
    as p(order_id, product_id, date, other_1, other_2)
on (s.product_id = p.product_id and s.order_id = p.order_id and s.date = p.date)
when matched then 
    update set s.other_1 = p.other_1, s.other_2 = p.other_2
when not matched by target then 
    insert(order_id, product_id, date, other_1, other_2)
    values(p.order_id, p.product_id, p.date, p.other_1, p.other_2)

这使用前三列作为主键;当元组已经存在时,列other_1other_2会用原本会插入的值进行更新。

相关问题