我有一个 SQLite 数据库,其中有一个表“myTable”,其中包含“日期”和“值”列。 “日期”记录是唯一的,即每个日期只有一行。
我还有一个文本文件,其中包含制表符分隔的“日期”/“值”对。
将文本文件中的数据追加到 SQLite 表中的最有效方法是什么,以便仅添加数据库中尚未存在的“日期”/“值”对?
我知道如何一次一行地执行此操作:检查数据库中是否存在“日期”/“值”对,如果不存在则插入它。但这似乎效率不高。
我正在考虑这样的事情:将文本文件读入字符串,将字符串转换为数组,将 DataTable 源设置为数组,使用 DataAdapter 从 DataTable 更新 SQLite 表。
这可以做到吗?如何做到?或者有更好的办法吗?
使用内置的 UPSERT、MERGE 或在 SQLites 情况下 CONFLICT 关键字能够插入或更新会更有效,例如:
INSERT INTO Data (Date, Value)
VALUES ('2024-12-09', 42.0)
ON CONFLICT(Date) DO UPDATE SET
Value = excluded.Value;
或者如果记录存在,则不执行任何操作:
INSERT INTO Data (Date, Value)
VALUES ('2024-12-09', 42.0)
ON CONFLICT(Date) DO NOTHING;
否则,您需要使用不太理想的 T-SQL 或 PL-SQL
IF EXISTS
,然后插入、更新或不执行任何操作。
这是 C# 代码,就像您希望的那样,我们将文本文件读入 DataTable,如果该日期没有值,则循环遍历表插入记录。
using System;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
class Program
{
static void Main()
{
// A shorthand way to read CSV file into DataTable
var dataTable = File.ReadAllLines("data.csv")
.Skip(1) // Skip header row
.Select(line => line.Split(','))
.Aggregate(new DataTable(), (dt, values) =>
{
if (dt.Columns.Count == 0)
{
dt.Columns.Add("Date", typeof(string));
dt.Columns.Add("Value", typeof(double));
}
dt.Rows.Add(values[0], double.Parse(values[1]));
return dt;
});
// Establish SQLite Connection, since its unmanaged wrap it with a Using to close and dispose
using var connection = new SQLiteConnection("Data Source=example.db");
connection.Open();
// Loop through each row
foreach (DataRow row in dataTable.Rows)
{
var sql = @"
INSERT INTO Data (Date, Value)
VALUES (@Date, @Value)
ON CONFLICT(Date) DO NOTHING";
using var cmd = new SQLiteCommand(sql, connection);
cmd.Parameters.AddWithValue("@Date", row["Date"]);
cmd.Parameters.AddWithValue("@Value", row["Value"]);
cmd.ExecuteNonQuery();
}
}
}