DuckDB .Net 客户端 - DuckDB.NET 基本用法

SQL 执行
要在 DuckDB.NET 中执行 SQL 语句,你需要创建一个 DuckDBConnection
对象,它作为执行 SQL 语句的入口点。创建连接后,创建一个与之关联的命令,并使用以下方法之一来执行该命令:
- ExecuteNonQuery - 执行不返回结果的 SQL,例如 DDL(数据定义语言)语句,或者通过执行
UPDATE
、INSERT
或DELETE
语句来更改数据。 - ExecuteScalar - 执行返回单个标量值的 SQL。
- ExecuteReader - 执行 SQL 并返回
DuckDBDataReader
,可用于处理结果集。
using var duckDBConnection = new DuckDBConnection("Data Source=file.db");
duckDBConnection.Open();
using var command = duckDBConnection.CreateCommand();
command.CommandText = "CREATE TABLE weather (city VARCHAR, temp_lo INTEGER, temp_hi INTEGER, prcp REAL, date DATE);";
var executeNonQuery = command.ExecuteNonQuery();
command.CommandText = "INSERT INTO weather VALUES ('Tbilisi', 41, 55, 0.1, '2020-04-02');";
executeNonQuery = command.ExecuteNonQuery();
command.CommandText = "INSERT INTO weather VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27');";
executeNonQuery = command.ExecuteNonQuery();
using var duckDBConnection = new DuckDBConnection("Data Source=file.db");
duckDBConnection.Open();
using var command = duckDBConnection.CreateCommand();
command.CommandText = "Select count(*) from weather";
var count = command.ExecuteScalar();
using var duckDBConnection = new DuckDBConnection("Data Source=file.db");
duckDBConnection.Open();
using var command = duckDBConnection.CreateCommand();
command.CommandText = "SELECT city, (temp_hi + temp_lo) / 2 AS temp_avg, date FROM weather;";
using var reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine("City: {0} Average Temperature: {1}, Date: {2}",
reader.GetString(0), reader.GetDouble(1), reader.GetDateTime(2));
}
参数化语句
在构建 SQL 命令时,始终使用参数化查询而不是字符串拼接。这有助于防止 SQL 注入,提高类型安全性,并可能提升性能。
DuckDB 支持在预编译语句中表示参数的三种语法:自动递增(?
)、位置($1
)和命名($param
)。DuckDB.NET 支持所有这三种语法:
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM person WHERE starts_with(name, $name_start_letter) AND age >= $minimum_age;";
command.Parameters.Add(new DuckDBParameter("minimum_age", 40));
command.Parameters.Add(new DuckDBParameter("name_start_letter", "B"));
using var reader = command.ExecuteReader();
批处理
你可以通过连接多个语句并用分号分隔,一次性执行多个语句:
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = "INSTALL httpfs;LOAD httpfs;";
command.ExecuteNonQuery();
如果这些语句返回数据,你可以使用 NextResult
方法处理多个结果集:
using var connection = new DuckDBConnection("DataSource=:memory:");
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM weather ORDER BY city, temp_lo;SELECT DISTINCT city FROM weather;";
using var reader = command.ExecuteNonQuery();
do
{
// 处理来自读取器的数据
} while (reader.NextResult());
物化模式和流模式
使用 DuckDBCommand
执行 Select
语句时,DuckDB.NET 默认将使用物化执行模式。在这种模式下,DuckDB 会在内存中获取整个结果集,这可能导致高内存使用。另一种选择是使用流执行模式,在这种情况下,DuckDB 将逐块获取结果集,使用较少的内存,但这可能会导致查询执行速度较慢。要使用流模式,将 UseStreamingMode
属性设置为 true
。
Publish on 2025-01-05,Update on 2025-02-10