跳转到内容

Formula 表达式

Formula 是一门小型、静态类型的表达式语言,不是任意 SQL。它使用带引号的 Field 名称以及固定的 SQLite 3.45 scalar function 子集。Runtime 会解析每个表达式并生成 SQL;Formula source 绝不会作为 SQL statement 直接执行。

  • 使用精确 display name 引用 Field:"累计阅读时长(秒)"
  • 使用 SQLite || 拼接文本。
  • 使用 IS NULLIS NOT NULL 检查 null。
  • 使用 CAST(value AS TEXT|INTEGER|REAL) 转换 value。
  • 使用 IIF(condition, trueValue, falseValue),或 searched CASE WHEN condition THEN value ELSE value END
  • arithmetic 支持 +-*/%;comparison 支持 ===!=<><<=>>=

声明的 result type 仍必须精确为 textnumberintegercheckboxdatedatetimeurl

分类 函数
Null 与分支 COALESCEIFNULLIIFNULLIF
数值 ABSCEILCEILINGFLOORROUNDSIGN、scalar MAX、scalar MIN
文本 CHARCONCATCONCAT_WSFORMATPRINTFINSTRLENGTHOCTET_LENGTHLOWERUPPERLTRIMRTRIMTRIMREPLACESUBSTRSUBSTRINGUNICODE
Pattern GLOBLIKE
检查 HEXQUOTETYPEOF
日期时间 DATEDATETIMETIMEJULIANDAYUNIXEPOCHSTRFTIMETIMEDIFF

函数名按 ASCII case-insensitive 处理。通过 static signature 检查的调用使用 SQLite 3.45 的 value、null、conversion、indexing 与 formatting behavior。需要特别注意:

  • CONCAT 将 non-null value 转为 text 并跳过 null。
  • SUBSTRSUBSTRING 和 SQLite 一样从一开始计数;negative position 与 length 也保留 SQLite 行为。
  • 内建 LOWERUPPER 只 fold ASCII character。
  • FORMATPRINTF 使用 SQLite formatting,而不是设备 locale。
  • date/time function 必须提供 time value。format 与 modifier 必须是 string literal;nowlocaltimeutcauto 会被拒绝,以避免结果依赖 clock、timezone 或 Host SQLite version。UNIXEPOCH 还会拒绝 subsecsubsecond,使 result 保持为 Integer。

下列表达式将 309299 秒格式化为 85小时55分钟,余下秒数按最近分钟取整:

IIF(
"累计阅读时长(秒)" IS NULL,
NULL,
FORMAT(
'%d小时%d分钟',
FLOOR("累计阅读时长(秒)" / 3600),
ROUND(("累计阅读时长(秒)" % 3600) / 60)
)
)

如果想丢弃余下秒数,请把 minute 部分的 ROUND 换成 FLOOR;对于 309299, 该结果是 85小时54分钟

Formula 排除 SQL statement、subquery、aggregate/window function、table-valued function、randomness、connection-state function、extension loading、JSON function、Host-defined function,以及仅由新版 SQLite 新增的函数。旧 Eidos-only 名称(例如 IFIS_NULLLOWER_ASCIIDATE_ADD_DAYS)不作为 alias;请使用 上面的 SQLite spelling。

更新较早的 draft File 时,请显式迁移表达式:

旧 spelling SQLite profile spelling
IF(C, A, B) IIF(C, A, B)
IS_NULL(X) X IS NULL
LOWER_ASCII(X) / UPPER_ASCII(X) LOWER(X) / UPPER(X)
DATE_ADD_DAYS(D, 7) DATE(D, '+7 days')
DATE_DIFF_DAYS(A, B) CAST(JULIANDAY(A) - JULIANDAY(B) AS INTEGER)
DATETIME_ADD_MILLISECONDS(D, 1000) DATETIME(D, '+1 second', 'subsec')
DATETIME_DIFF_MILLISECONDS(A, B) CAST((JULIANDAY(A) - JULIANDAY(B)) * 86400000 AS INTEGER)