Skip to content

Expression API

Expression API允许用户动态构建表达式,这些表达式通常就是配合Relational API中的各种操作来构造 SELECT 语句。Expression API 提供了五种表达式抽象:

  • ColumnExpression(column:str): 按照名称引用列,说白了就是对列名进行包装为 Expression 对象
  • StarExpression(exclude:list): 所有列,可以使用 exclude 来指定需要排除的列,在大多数时候等价于 *[ColumnExpression(column_1) ....]
  • ConstantExpression(value): 常量表达式,说白了就是将常量包装为 Expression 对象
  • CaseExpression(condition: Expression, then_value: ConstantExpression): 分支表达式,SQL 里面的 IF ELSE 语句
  • FunctionExpression(func_name:str, *args: Expression): 构造函数表达式,func_name 必须是 SQL 函数或者 UDF 函数

以上五个表达式对象还绑定了一些通用的操作:

  • alias(name:str): 别名,对应的 AS 操作
  • cast(type: DuckDBPyType): 类型转换,对应的 CAST 或者 ::text 这样的操作
  • isin(*expres: Expression): IN 表达式,其中可以是结果为列表的其他表达式
  • isnotin(*expres: Expression): NOT IN 表达式,其中可以是结果为列表的其他表达式
  • isnotnull(): 检测表达式是否不是 NULL
  • isnull(): 检测表达式是否是 NULL

如果表达式提供给 DuckDBPyRelation.order() 时,可以执行以下操作:

  • asc(): 指示表达式升序排序
  • desc(): 指示表达式降序排列
  • nulls_first(): 指示表达式中的 null 值位于非 null 值之前
  • nulls_last(): 指示表达式中的 null 值位于非 null 值之后

ColumnExpression 和 StarExpression

这两个都是用于选择列的表达式,说白了他就是 SQL 中列的双引号:

Python
import duckdb
import pandas as pd

df = pd.DataFrame(
    {"a": [1, 2, 3, 4], "b": [True, None, False, True], "c": [42, 21, 13, 14]}
)

# selecting a single column
col = duckdb.ColumnExpression("a")
res = duckdb.from_df(df).select(col).fetchall()
print(res)

# selecting multiple columns
col_list = [
    duckdb.ColumnExpression("a") * 10,
    duckdb.ColumnExpression("b").isnull(),
    duckdb.ColumnExpression("c") + 5,
]

res = duckdb.from_df(df).select(*col_list).fetchall()
print(res)

# StarExpression 能够选择所有的,可以通过 exclude 来排除指定列
star = duckdb.StarExpression(exclude=["b"])
res = duckdb.df(df).select(star).fetchall()
print(res)

    [(1,), (2,), (3,), (4,)]
    [(10, False, 47), (20, True, 26), (30, False, 18), (40, False, 19)]
    [(1, 42), (2, 21), (3, 13), (4, 14)]

SQL 中任何需要列名(标准需要双引号)的地方都需要使用列表达式封装。如果需要对列进行详细的处理就使用 ColumnExpression,如果只是想处理多列就使用 StarExpression 他比较方便。

ConstantExpression

常量表达式,说白了就是 SQL 中对常量的单引号:

Python
import duckdb
import pandas as pd

df = pd.DataFrame(
    {"a": [1, 2, 3, 4], "b": [True, None, False, True], "c": [42, 21, 13, 14]}
)

const = duckdb.ConstantExpression("hello")
res = duckdb.df(df).select(const).fetchall()
print(res)

    [('hello',), ('hello',), ('hello',), ('hello',)]

SQL 中任何需要常量的地方都需要使用常量表达式封装

CaseExpression

分支表达式,他等价于 SQL 语句中的:

SQL
CASE
    -- 条件表达式
    WHEN(condition)
    -- 如果条件表达式为 True
    THEN value
    -- 如果条件表达式为 False
    ELSE else_value
END

当然 ELSE 需要配合 otherwise(value) 函数来使用,对于 CaseExpression 则只针对于 condition 和 WHEN 中的 value:

Python
import duckdb
import pandas as pd
from duckdb import ConstantExpression, ColumnExpression, CaseExpression

df = pd.DataFrame(
    {"a": [1, 2, 3, 4], "b": [True, None, False, True], "c": [42, 21, 13, 14]}
)

hello = ConstantExpression("hello")
world = ConstantExpression("world")

case = CaseExpression(condition=ColumnExpression("b") == False, value=world).otherwise(
    hello
)
res = duckdb.df(df).select(case).fetchall()
print(res)

    [('hello',), ('hello',), ('world',), ('hello',)]

FunctionExpression

包含函数调用,他可以通过提供函数名称和任意数量的表达式作为参数来构造表达式:

Python
import duckdb
import pandas as pd
from duckdb import ConstantExpression, ColumnExpression, FunctionExpression

df = pd.DataFrame(
    {
        "a": [
            "test",
            "pest",
            "text",
            "rest",
        ]
    }
)

ends_with = FunctionExpression(
    "ends_with", ColumnExpression("a"), ConstantExpression("est")
)
res = duckdb.df(df).select(ends_with).fetchall()
print(res)

    [(True,), (True,), (False,), (True,)]

这其中的函数名必须是 SQL 的内置函数以及用户自定义的过程函数(UDF)