关系API是一种替代API,可用于逐步构建查询。该API围绕DuckDBPyRelation
节点展开。这些关系可以看作是SQL查询的符号表示。它们不持有任何数据——并且在调用触发执行的方法之前,不会执行任何操作。
构建关系
关系可以通过使用duckdb.sql
方法从SQL查询中创建。或者,它们可以通过各种数据摄取方法(read_parquet
、read_csv
、read_json
)创建。
例如,这里我们从SQL查询创建一个关系:
import duckdb
rel = duckdb.sql("SELECT * FROM range(10_000_000_000) tbl(id)")
rel.show()
┌────────────────────────┐
│ id │
│ int64 │
├────────────────────────┤
│ 0 │
│ 1 │
│ 2 │
│ 3 │
│ 4 │
│ 5 │
│ 6 │
│ 7 │
│ 8 │
│ 9 │
│ · │
│ · │
│ · │
│ 9990 │
│ 9991 │
│ 9992 │
│ 9993 │
│ 9994 │
│ 9995 │
│ 9996 │
│ 9997 │
│ 9998 │
│ 9999 │
├────────────────────────┤
│ ? rows │
│ (>9999 rows, 20 shown) │
└────────────────────────┘
注意我们是如何构建一个计算大量数据(100亿行或74 GB数据)的关系的。这个关系是即时构建的——我们甚至可以即时打印这个关系。
当使用show
打印关系或在终端中显示它时,会获取前10K
行。如果有超过10K
行,输出窗口将显示>9999 rows
(因为关系中的行数未知)。
数据摄取
在SQL查询之外,提供了以下方法从外部数据构建关系对象。
from_arrow
from_df
read_csv
read_json
read_parquet
SQL查询
关系对象可以通过SQL进行查询,通过替换扫描。如果你有一个存储在变量中的关系对象,你可以像引用SQL表一样引用该变量(在FROM
子句中)。这允许你使用关系对象逐步构建查询。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
duckdb.sql("SELECT sum(id) FROM rel").show()
┌──────────────┐
│ sum(id) │
│ int128 │
├──────────────┤
│ 499999500000 │
└──────────────┘
操作
可以对关系执行许多操作。这些都是运行SQL查询的简写——并且它们本身将再次返回关系。
aggregate(expr, groups = {})
对关系应用一个(可选的)分组聚合。系统将自动对任何非聚合列进行分组。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
rel.aggregate("id % 2 AS g, sum(id), min(id), max(id)")
┌───────┬──────────────┬─────────┬─────────┐
│ g │ sum(id) │ min(id) │ max(id) │
│ int64 │ int128 │ int64 │ int64 │
├───────┼──────────────┼─────────┼─────────┤
│ 0 │ 249999500000 │ 0 │ 999998 │
│ 1 │ 250000000000 │ 1 │ 999999 │
└───────┴──────────────┴─────────┴─────────┘
except_(rel)
选择第一个关系中所有不在第二个关系中出现的行。这两个关系必须具有相同数量的列。
import duckdb
r1 = duckdb.sql("SELECT * FROM range(10) tbl(id)")
r2 = duckdb.sql("SELECT * FROM range(5) tbl(id)")
r1.except_(r2).show()
┌───────┐
│ id │
│ int64 │
├───────┤
│ 5 │
│ 6 │
│ 7 │
│ 8 │
│ 9 │
└───────┘
filter(condition)
将给定条件应用于关系,过滤掉不满足条件的任何行。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
rel.filter("id > 5").limit(3).show()
┌───────┐
│ id │
│ int64 │
├───────┤
│ 6 │
│ 7 │
│ 8 │
└───────┘
intersect(rel)
选择两个关系的交集——返回在两个关系中同时出现的所有行。关系必须具有相同数量的列。
import duckdb
r1 = duckdb.sql("SELECT * FROM range(10) tbl(id)")
r2 = duckdb.sql("SELECT * FROM range(5) tbl(id)")
r1.intersect(r2).show()
┌───────┐
│ id │
│ int64 │
├───────┤
│ 0 │
│ 1 │
│ 2 │
│ 3 │
│ 4 │
└───────┘
join(rel, condition, type = "inner")
合并两个关系,根据提供的条件进行连接。
import duckdb
r1 = duckdb.sql("SELECT * FROM range(5) tbl(id)").set_alias("r1")
r2 = duckdb.sql("SELECT * FROM range(10, 15) tbl(id)").set_alias("r2")
r1.join(r2, "r1.id + 10 = r2.id").show()
┌───────┬───────┐
│ id │ id │
│ int64 │ int64 │
├───────┼───────┤
│ 0 │ 10 │
│ 1 │ 11 │
│ 2 │ 12 │
│ 3 │ 13 │
│ 4 │ 14 │
└───────┴───────┘
limit(n, offset = 0)
选择前n行,可选地偏移offset。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
rel.limit(3).show()
┌───────┐
│ id │
│ int64 │
├───────┤
│ 0 │
│ 1 │
│ 2 │
└───────┘
order(expr)
按给定的表达式集对关系进行排序。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
rel.order("id DESC").limit(3).show()
┌────────┐
│ id │
│ int64 │
├────────┤
│ 999999 │
│ 999998 │
│ 999997 │
└────────┘
project(expr)
将给定的表达式应用于关系中的每一行。
import duckdb
rel = duckdb.sql("SELECT * FROM range(1_000_000) tbl(id)")
rel.project("id + 10 AS id_plus_ten").limit(3).show()
┌─────────────┐
│ id_plus_ten │
│ int64 │
├─────────────┤
│ 10 │
│ 11 │
│ 12 │
└─────────────┘
union(rel)
合并两个关系,返回r1
中的所有行,然后是r2
中的所有行。这些关系必须具有相同数量的列。
import duckdb
r1 = duckdb.sql("SELECT * FROM range(5) tbl(id)")
r2 = duckdb.sql("SELECT * FROM range(10, 15) tbl(id)")
r1.union(r2).show()
┌───────┐
│ id │
│ int64 │
├───────┤
│ 0 │
│ 1 │
│ 2 │
│ 3 │
│ 4 │
│ 10 │
│ 11 │
│ 12 │
│ 13 │
│ 14 │
└───────┘
结果输出
关系的结果可以转换为各种类型的Python结构,更多信息请参见结果转换页面。
关系的结果也可以使用以下方法直接写入文件。