SET dialect = 'clickhouse' 可切换回 ClickHouse 方言。KQL 方言处于启用状态时,SET 是唯一可识别的 SQL 语句,因此会话始终可以退出该方言。
支持的内容
这是一个有意限定的小型子集。KQL 构造要么按 Kusto 文档描述的语义进行转换, 要么按名称拒绝并报出解析错误——绝不会进行静默的近似处理。 如果查询能够解析,其结果应与 Kusto 的结果一致。 数据源:表名、print、datatable、range、括号括起的管道以及 union。
range 可以从一个数值按数值递增、从日期时间按时间跨度递增,或从时间跨度按
时间跨度递增。
运算符:where / filter、extend、project、project-away、project-keep、
project-rename、summarize、sort by / order by、take / limit、top、distinct、
count、mv-expand、join、union、as、render。
标量运算符:==、!=、<、<=、>、>=、=~、!~、in、in~、between、
contains、startswith、endswith、has、hasprefix、hassuffix,以及它们的 _cs
(区分大小写) 和 ! (取反) 形式,还有 has_any、has_all 和 matches regex。
in 和 !in 还可接受表表达式,其第一列提供值
(x in (T | project key)) ;in~ 仅接受列表。若 in (...) 中单独出现的名称未被任何
let 绑定,则会被解析为列,因为解析器没有 schema 来区分列和表;
请使用 let 绑定该表、对其进行限定 (db.table) ,或添加管道以使用表表达式形式。
语句:let,用于绑定标量、完整的表表达式或函数:
T: (*) 或 T: (col: type, ...) 且必须置于前面的表格参数。指定列名的表格参数仅向函数体公开参数中的这些列,因此即使实际参数恰好包含某个未声明的列,函数体读取该列也会被拒绝;T: (*) 则会按原样传递参数。声明的类型会在调用边界处强制校验:类型不属于所声明 KQL 类型的参数 (或表格参数中声明的列) 会被拒绝;会应用无损转换,例如将 long 转换为 real;而不符合声明类型的值 (例如 int 溢出) 会报错,而不会被静默截断。参数可通过名称以任意顺序传递 (f(c = 7, a = 12)) 。函数体由任意数量的 let 语句和一个表达式组成,并且可以访问其外围作用域中的绑定。函数体为管道的函数返回的是表而非值,因此在需要表达式的位置会被拒绝,例如 extend、where 或 print。无参数函数可以带或不带括号调用。接受 view ();由于此处不会解析 union * 通配符,它与 () 含义相同。与 Kusto 一样,不支持递归。
let 仅在其后的那条语句中绑定名称,因为一条 KQL 语句对应一个 ClickHouse 查询——这也避免了绑定泄漏到并发查询中。两个语句都需要的名称必须绑定两次。
字面量:字符串 (包括原样字符串 @'...') 、数字、datetime(...)、guid(...)、时间跨度,如 1d / 2.5h / 500ms,以及 dynamic([...]) 数组。
约 130 个标量函数和聚合函数会被翻译。与 Kusto 一样,聚合函数只能在 summarize 的聚合列表中调用;print count() 会被拒绝,而不会传递给同名的 ClickHouse 聚合函数。
ClickHouse 函数也可使用。KQL registry 不识别的名称会按你写下的拼写传递给 ClickHouse,因此查询可以使用 server 提供的任何功能:
range 是最典型的例子——在 Kusto 中,range(1, 3, 1) 的结果是 [1, 2, 3],而在
ClickHouse 中则是 [1, 2],因此在 KQL 中写出它会报错,而不是返回错误的结果。
与 Kusto 参考文档的覆盖对比
以 Microsoft 自身的索引为基准 (表格运算符、 标量函数、 聚合函数) :
支持的运算符包括 Microsoft 自身的 Learn 常用运算符 教程中介绍的运算符,
以及
datatable、range、print、union 和 join——足以支持该教程和 KQL Quick Reference 中逐步构建的查询形态。
不支持的内容
会报解析错误而被拒绝,不会被错误翻译:- 运算符:
search、parse、mv-apply、lookup、evaluate、invoke、facet、top-nested、make-series、sample、serialize、partition,以及作为运算符的range。 - 函数:
series_*家族、bag_*/pack_*、parse_url、parse_csv、parse_json、todynamic、toscalar、format_timespan、format_datetime、extract_all、range、percentiles*家族以及row_*窗口函数。 (format_datetime和extract_all会被拒绝,而非近似转换:Kusto 的yyyy-MM-dd格式说明符不同于 ClickHouse,且 Kusto 的extract_all会为每个捕获组返回一个 数组。) - 与含义不同的 ClickHouse 函数同名的 Kusto 名称:
range(如上所述) 、repeat、replace、translate和materialize。直接保留这些名称会在不显眼的情况下计算出不同结果——Kusto 的repeat(1, 3)返回数组[1, 1, 1],而 ClickHouse 的repeat用于重复字符串——因此会按名称拒绝这些函数。 - 接受或返回 GeoJSON 的地理空间函数——所有
geo_*_to_central_point,以及 所有对多边形和线进行操作的函数。处理普通经度/纬度的 Point、geohash 和 H3 函数 受支持。geo_point_to_s2cell不受支持:ClickHouse 不提供 S2 token 形式。 dynamic对象 (dynamic({"a": 1})) 、成员访问 (x.y) 以及按键查找 (x['k']) 。仅支持将dynamic数组映射为 ClickHouseArray。作为 声明类型的dynamic——用于datatableschema、typeof(...)或函数参数—— 同样会被拒绝:该注解未携带元素类型,因此无法进行忠实映射。- 跨集群和跨数据库引用,例如
cluster(...)和database(...)。 - 查询和
join提示 (hint.strategy、hint.shufflekey等) 。 - 运算符选项:
mv-expand ... to typeof(T)/limit N/bagexpansion、summarize提示、union kind=/withsource=/isfuzzy=、join hint.*。 project-away和project-keep中的 wildcard 列模式 (project-away Tmp*) : 展开这类模式需要 schema,但在解析时 schema 不可见。请明确列出各列。- 完全不支持
evaluate插件机制,因此bag_unpack、pivot、narrow、python、R及其他插件也不支持。 - Application 语句:
alias database、declare pattern、declare query_parameters、restrict access to。 - 混淆字符串字面量 (
h"...") 和多行字面量 (三个反引号) 。
值得了解的行为
- 时间跨度是
Interval值。1d会变为toIntervalNanosecond(86400000000000)。 设置interval_output_format = 'kusto'可按 Kusto 的格式将其呈现为1.00:00:00,而非 数值。 - 除法遵循 Kusto 的规则:
7 / 2等于3,因为两个操作数都是整数;时间跨度除以时间跨度则得到其实数比值 (15ms / 10ms等于1.5) 。这由kqlDivide实现,其根据参数类型作出判断。 - 两个日期时间相减会得到秒数,而 Kusto 会得到时间跨度。 时间跨度的加减则符合预期。
sort默认按降序排列,与 SQL 不同,并会将 null 排在较小值的一端。project-rename会将重命名后的列移至行末。Kusto 会保留其 原始位置;要复现这一行为,需要在解析时获知 schema。union要求操作数具有兼容的 schema。 Kusto 会扩展为所有列的并集, 并以 null 填充;ClickHouse 的UNION ALL则不会。- 字符串运算符是匹配函数,而非
LIKE模式。contains '50%'会查找 字面量百分号。 geo_*与 Kusto 一样,先接受经度,再接受纬度。geo_distance_2points使用 ClickHouse 的greatCircleDistance,这是一种快速近似算法,与 Kusto 的结果在 第四位有效数字上有所差异——在 1500 km 距离上约相差 600 m——而use_spheroid = true会选择geoDistance,即椭球体公式,与 Kusto 相同。完全一致并非目标: 这些函数通常用于筛选,而非报告。请注意,超出 [-180, 180] 或 [-90, 90] 范围的坐标会产生 无意义的数值,而不是 Kusto 返回的 null: 两个 ClickHouse 函数都不会检查其参数是否在范围内,而进行检查每行需额外执行八次 比较。dayofweek()返回时间跨度,而非数值:星期一为1.00:00:00。tohex()会以 64 位宽度呈现负值。 Kusto 会按 参数自身类型的宽度呈现,而这一信息在解析时不可见。- 日期时间是真正的
DateTime64值,因此会按 ClickHouse 的方式打印 (2017-01-01 00:00:00),而非 Kusto 的2017-01-01T00:00:00.0000000。之前的 实现会生成格式化的字符串,看起来像 Kusto,但无法像日期时间一样进行比较 或排序。 - ClickHouse 的参数化聚合函数 (
quantileExact(0.5)(x)) 没有对应的 KQL 写法。 请使用命名替代方案,例如medianExact(x)。