ANSI 模式旨在使 SQL 语法和执行时的行为,与 ANSI 标准或其他主流数据库更加一致。
通过dialect_type
选项,可以使ByteHouse 在 ANSI 模式 和 ClickHouse 模式之间切换,例如:
SET dialect_type = 'CLICKHOUSE'; SET dialect_type = 'ANSI';
ByteHouse 默认使用的是 ClickHouse 模式。
说明
推荐使用上述的 SET 命令设置 dialect_type
,不建推荐通过查询级别的 SETTINGS 来设置,如:
SELECT ... SETTINGS dialect_type = 'ANSI';
在实现方面,许多 ANSI 功能由单独的子选项控制,dialect_type 可以视为这些子选项的总和。 如果需要,可以使用子选项来控制 ANSI 模式下的特定行为,例如:
SET dialect_type = 'ANSI'; SELECT ... SETTINGS join_use_nulls = 0;
下面列出了 ANSI 相关功能。 如果此功能有单独的子选项,则由 相关子选项 进行解释 。
默认模式下的默认数据类型不可为空。 但 ANSI 标准要求它可以为空。
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
添加了时间 Time 数据类型。
支持时区的时间数据类型是 ANSI SQL 标准,受 MySQL、PostgreSQL 支持。 时间数据类型的格式为 hh:mm:ss[.nnnnnnn]。 内部表示为 Int64。 它的精度以scale作为参数。 Scale 的最大值为 9,等于小数点后的位数;默认值为 3。
查询示例:使用Time数据类型的函数示例。
select toHour('11:20:30'::Time); select Hour('11:20:30'::Time); select toMinute('11:20:30'::Time); select Minute('11:20:30'::Time); select toSecond('11:20:30'::Time); select Second('11:20:30'::Time); select addYears('11:20:30'::Time(3), 5); select addYears('11:20:30'::Time(4), 20); select subtractYears('11:20:30'::Time(5), 5); select subtractYears('11:20:30'::Time(6), 20); select addMonths('11:20:30'::Time(3), 5); select addMonths('11:20:30'::Time(4), 20); select subtractMonths('11:20:30'::Time(5), 5); select subtractMonths('11:20:30'::Time(6), 20); select addDays('11:20:30'::Time(3), 5); select addDays('11:20:30'::Time(4), 20); select subtractDays('11:20:30'::Time(5), 5); select subtractDays('11:20:30'::Time(6), 20); select addHours('11:20:30'::Time(3), 5); select addHours('11:20:30'::Time(4), 20); select subtractHours('11:20:30'::Time(5), 5); select subtractHours('11:20:30'::Time(6), 20); select addMinutes('11:20:30'::Time(2), 50); select addMinutes('11:20:30'::Time(3), 2000); select subtractMinutes('11:20:30'::Time, 50); select subtractMinutes('11:20:30'::Time(1), 5000); select addSeconds('11:20:30'::Time, 500); select addSeconds('11:20:30'::Time(2), 200000); select subtractSeconds('11:20:30'::Time, 500); select subtractSeconds('11:20:30'::Time(1), 500000);
DateTime64 类型支持的数据范围为: [1900-01-01 00:00:00, 2299-12-31 23:59:59.99999999] 。
ClickHouse 模式下,隐式类型转换无法发生在一些数值类型间,如果类型转换会导致精度损失(如 Decimal & Float, Int64 & Float)或性能下降(如 UInt64 & Ints)。ANSI 模式下,这一类隐式转换被允许进行。
相关子选项:allow_extended_type_conversion: 0 / 1
样例查询 1:Decimal 和 Float 的隐式转换
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
样例查询 2:Int64 和 Float 的隐式转换
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
样例查询 3:UInt64 和 Int 的隐式转换
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
默认情况下,带有小数点的数字文字被解析为浮点类型。 在 ANSI 模式下,文字被解析为Decimal 定点数据类型以确保精度。
查询示例:
| |
---|---|
默认模式下的输出:Float64 | 以ANSI模式输出:Decimal(18, 1) |
当存在重名的 alias 和表字段时,在 CLICKHOUSE 模式下,会优先解析为 alias;在 ANSI 模式下,则会优先解析为表字段。这一规则不适用 ORDER BY 子句。
相关子选项:prefer_column_name_to_alias: 0 / 1
样例查询 1:
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
样例查询 2:prefer column name to alias 规则不适用 ORDER BY 子句,两种模式下 a 都被解析为 alias
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
ClickHouse 模式下,当 join 两表存在重名字段时,引用该名字被解释成对第一张表字段的引用。这一特性和主流数据库不符,且在多表 join 的情况下语义更加模糊。ANSI 模式下,禁止对歧义名字的引用。
样例查询:
| |
---|---|
ClickHouse 模式下输出: | ANSI 模式下输出: |
在 ANSI 模式下,如果 CAST 函数的参数为可空 Nullable 类型,则结果类型仍为 Nullable。
相关子选项:cast_keep_nullable
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
默认模式下,小数除法结果类型的小数位数为:S = S1。 当 S1 不够大时,这会导致较大的舍入误差。 在 ANSI 模式下,比例值为:S = max (6, S1)。
相关子选项:decimal_division_use_extended_scale
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
一些 decimal 小数场景由于重新缩放容易出现溢出错误。在ANSI模式下,会自动提升底层存储类型以最小化溢出。这些场景包括:
相关子选项:decimal_arithmetic_promote_storage
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
在 ANSI 模式下,无论帧类型如何,所有ORDER BY
表达式中具有相同值的行都被视为相同行。
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
在 ANSI 模式下,与常规 =
运算符一样,比较两个值的结果为 0(不等于)或 1(等于); 换句话说:'a' <=> 'b'
产生 0
,'a' <=> 'a'
产生 1
。
与常规=
运算符不同,NULL
的值没有特殊含义,因此它永远不会产生NULL
作为结果的情况;因此:'a'<=>NULL
产生0
,NULL<=>NULL
产生1
。
查询示例
| |
---|---|
以ANSI模式输出: |
ANSI 模式支持关联子查询。
查询示例:
INSERT INTO orders(order_id, customer_id, amount) VALUES (1, 101, 100), (2, 101, 120), (3, 102, 30); SELECT order_id FROM customers x WHERE amount = (SELECT avg(amount)FROM customers yWHERE x.customer_id = y.customer_id)
在默认模式下,对于没有连接记录的情况,外连接默认为0或"。在ANSI模式下,默认值为 NULL。
相关子选项:join_use_nulls
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
在默认模式下,可以指定外连接的条件。在ANSI模式下,外连接不允许使用指定条件。
查询示例1:左连接时,连接键的输出结果为左表数据
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
查询示例2:右连接时,连接键的输出结果为右表数据
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
查询示例3:Full join时,join键的输出结果为左右表数据
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
在默认模式下,当使用键的连接具有相同的别名时,该别名对左表可见。此功能在 ANSI 模式下禁用。
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |
在 ANSI 模式下,支持哈希连接/嵌套循环连接/合并连接。
示例
CREATE TABLE nse_lhs (key int, value Nullable(UInt8)) ENGINE=CnchMergeTree order by key; CREATE TABLE nse_rhs (key int, value Nullable(UInt8)) ENGINE=CnchMergeTree order by key; INSERT INTO nse_lhs VALUES (1,1) (2, 2) (3, NULL) (4, NULL) (5,6) (6, NULL); INSERT INTO nse_rhs VALUES (1,1) (2, NULL) (3, 2) (4, NULL) (5,7) (6, 0); select '# Null safe join (equi hash join)'; SELECT key, value FROM nse_lhs JOIN nse_rhs ON nse_lhs.key=nse_rhs.key AND nse_rhs.value IS NOT DISTINCT FROM nse_lhs.value; select ''; SET join_algorithm='partial_merge'; select '# Null safe join (merge join)'; SELECT key, value FROM nse_lhs JOIN nse_rhs ON nse_lhs.key=nse_rhs.key AND nse_rhs.value<=>nse_lhs.value; SET join_algorithm='nested_loop'; select '# Null safe join (nested loop join)'; SELECT key, value FROM nse_lhs JOIN nse_rhs ON nse_lhs.key=nse_rhs.key AND nse_rhs.value<=>nse_lhs.value; SQL
--以ANSI模式输出: # USING <=> hash 1 1 4 \N# USING <=> partial_merge 1 1 4 \N# USING <=> nested_loop 1 1 4 \N
默认模式下,对于 union / intersect / except 操作,如果没有显示指定 all / distinct(去重) 语义,则默认为 all 语义; ANSI模式下,默认为 distinct 语义;
查询示例
| |
---|---|
默认模式下的输出: | 以ANSI模式输出: |