跳至主要内容

算术函数

算术函数适用于类型为UInt8UInt16UInt32UInt64Int8Int16Int32Int64Float32Float64的任意两个操作数。

在执行操作之前,两个操作数都将转换为结果类型。结果类型如下确定(除非在下面的函数文档中另有说明)

  • 如果两个操作数都最多为 32 位宽,则结果类型的尺寸将是两个操作数中较大操作数的下一个更大类型的尺寸(整数尺寸提升)。例如,UInt8 + UInt16 = UInt32Float32 * Float32 = Float64
  • 如果其中一个操作数有 64 位或更多位,则结果类型的尺寸将与两个操作数中较大操作数的尺寸相同。例如,UInt32 + UInt128 = UInt128Float32 * Float64 = Float64
  • 如果其中一个操作数是有符号的,则结果类型也将是有符号的,否则它将是无符号的。例如,UInt32 * Int32 = Int64

这些规则确保结果类型将是最小的可以表示所有可能结果的类型。虽然这会带来在值范围边界附近溢出的风险,但它确保可以使用 64 位的最大本机整数宽度快速执行计算。此行为还保证与许多其他提供 64 位整数 (BIGINT) 作为最大整数类型的数据库的兼容性。

示例

SELECT toTypeName(0), toTypeName(0 + 0), toTypeName(0 + 0 + 0), toTypeName(0 + 0 + 0 + 0)
┌─toTypeName(0)─┬─toTypeName(plus(0, 0))─┬─toTypeName(plus(plus(0, 0), 0))─┬─toTypeName(plus(plus(plus(0, 0), 0), 0))─┐
│ UInt8 │ UInt16 │ UInt32 │ UInt64 │
└───────────────┴────────────────────────┴─────────────────────────────────┴──────────────────────────────────────────┘

溢出与 C++ 中的方式相同。

plus

计算两个值 ab 的和。

语法

plus(a, b)

可以将整数和日期或日期时间相加。前者操作增加日期的天数,后者操作增加日期时间的秒数。

别名:a + b(运算符)

minus

计算两个值 ab 的差。结果始终是有符号的。

类似于 plus,可以从日期或日期时间中减去一个整数。

语法

minus(a, b)

别名:a - b(运算符)

multiply

计算两个值 ab 的积。

语法

multiply(a, b)

别名:a * b(运算符)

divide

计算两个值 ab 的商。结果类型始终为Float64。整数除法由 intDiv 函数提供。

除以 0 返回 inf-infnan

语法

divide(a, b)

别名:a / b(运算符)

intDiv

执行两个值 a 除以 b 的整数除法,即计算向下舍入到下一个最小整数的商。

结果与被除数(第一个参数)具有相同的宽度。

当除以零时、商不适合被除数的范围时或当将最小的负数除以负一时,会抛出异常。

语法

intDiv(a, b)

示例

查询

SELECT
intDiv(toFloat64(1), 0.001) AS res,
toTypeName(res)
┌──res─┬─toTypeName(intDiv(toFloat64(1), 0.001))─┐
│ 1000 │ Int64 │
└──────┴─────────────────────────────────────────┘
SELECT
intDiv(1, 0.001) AS res,
toTypeName(res)
Received exception from server (version 23.2.1):
Code: 153. DB::Exception: Received from localhost:9000. DB::Exception: Cannot perform integer division, because it will produce infinite or too large number: While processing intDiv(1, 0.001) AS res, toTypeName(res). (ILLEGAL_DIVISION)

intDivOrZero

intDiv 相同,但在除以零或将最小的负数除以负一时返回零。

语法

intDivOrZero(a, b)

isFinite

如果 Float32 或 Float64 参数不是无限的并且不是 NaN,则返回 1,否则此函数返回 0。

语法

isFinite(x)

isInfinite

如果 Float32 或 Float64 参数是无限的,则返回 1,否则此函数返回 0。请注意,对于 NaN 返回 0。

语法

isInfinite(x)

ifNotFinite

检查浮点值是否有限。

语法

ifNotFinite(x,y)

参数

  • x — 要检查无限的值。Float*
  • y — 回退值。Float*

返回值

  • 如果 x 是有限的,则为 x
  • 如果 x 不是有限的,则为 y

示例

查询

SELECT 1/0 as infimum, ifNotFinite(infimum,42)

结果

┌─infimum─┬─ifNotFinite(divide(1, 0), 42)─┐
│ inf │ 42 │
└─────────┴───────────────────────────────┘

您可以使用三元运算符获得类似的结果:isFinite(x) ? x : y

isNaN

如果 Float32 和 Float64 参数是 NaN,则返回 1,否则此函数返回 0。

语法

isNaN(x)

modulo

计算两个值 a 除以 b 的余数。

如果两个输入都是整数,则结果类型为整数。如果其中一个输入是浮点数,则结果类型为Float64

余数像在 C++ 中一样计算。截断除法用于负数。

当除以零或当将最小的负数除以负一时,会抛出异常。

语法

modulo(a, b)

别名:a % b(运算符)

moduloOrZero

modulo类似,但在除数为零时返回零。

语法

moduloOrZero(a, b)

positiveModulo(a, b)

modulo类似,但始终返回非负数。

此函数比 modulo 慢 4-5 倍。

语法

positiveModulo(a, b)

别名

  • positive_modulo(a, b)
  • pmod(a, b)

示例

查询

SELECT positiveModulo(-1, 10)

结果

┌─positiveModulo(-1, 10)─┐
│ 9 │
└────────────────────────┘

negate

取反值 a。结果始终是有符号的。

语法

negate(a)

别名:-a

abs

计算 a 的绝对值。如果 a 是无符号类型,则没有效果。如果 a 是有符号类型,则返回无符号数。

语法

abs(a)

gcd

返回两个值 ab 的最大公约数。

当除以零或当将最小的负数除以负一时,会抛出异常。

语法

gcd(a, b)

lcm(a, b)

返回两个值 ab 的最小公倍数。

当除以零或当将最小的负数除以负一时,会抛出异常。

语法

lcm(a, b)

max2

返回两个值 ab 中较大的一个。返回值的类型为Float64

语法

max2(a, b)

示例

查询

SELECT max2(-1, 2);

结果

┌─max2(-1, 2)─┐
│ 2 │
└─────────────┘

min2

返回两个值 ab 中较小的一个。返回值的类型为Float64

语法

min2(a, b)

示例

查询

SELECT min2(-1, 2);

结果

┌─min2(-1, 2)─┐
│ -1 │
└─────────────┘

multiplyDecimal

将两个十进制数 ab 相乘。结果值的类型将为Decimal256

可以通过 result_scale 显式指定结果的刻度。如果未指定 result_scale,则假定其为输入值的最高刻度。

此函数的工作速度明显慢于通常的 multiply。如果不需要控制结果精度和/或需要快速计算,请考虑使用 multiply

语法

multiplyDecimal(a, b[, result_scale])

参数

返回值

示例

┌─multiplyDecimal(toDecimal256(-12, 0), toDecimal32(-2.1, 1), 1)─┐
│ 25.2 │
└────────────────────────────────────────────────────────────────┘

与常规乘法的区别

SELECT toDecimal64(-12.647, 3) * toDecimal32(2.1239, 4);
SELECT toDecimal64(-12.647, 3) as a, toDecimal32(2.1239, 4) as b, multiplyDecimal(a, b);

结果

┌─multiply(toDecimal64(-12.647, 3), toDecimal32(2.1239, 4))─┐
│ -26.8609633 │
└───────────────────────────────────────────────────────────┘
┌───────a─┬──────b─┬─multiplyDecimal(toDecimal64(-12.647, 3), toDecimal32(2.1239, 4))─┐
│ -12.647 │ 2.1239 │ -26.8609 │
└─────────┴────────┴──────────────────────────────────────────────────────────────────┘
SELECT
toDecimal64(-12.647987876, 9) AS a,
toDecimal64(123.967645643, 9) AS b,
multiplyDecimal(a, b);

SELECT
toDecimal64(-12.647987876, 9) AS a,
toDecimal64(123.967645643, 9) AS b,
a * b;

结果

┌─────────────a─┬─────────────b─┬─multiplyDecimal(toDecimal64(-12.647987876, 9), toDecimal64(123.967645643, 9))─┐
│ -12.647987876 │ 123.967645643 │ -1567.941279108 │
└───────────────┴───────────────┴───────────────────────────────────────────────────────────────────────────────┘

Received exception from server (version 22.11.1):
Code: 407. DB::Exception: Received from localhost:9000. DB::Exception: Decimal math overflow: While processing toDecimal64(-12.647987876, 9) AS a, toDecimal64(123.967645643, 9) AS b, a * b. (DECIMAL_OVERFLOW)

divideDecimal

将两个十进制数 ab 相除。结果值的类型将为Decimal256

可以通过 result_scale 显式指定结果的刻度。如果未指定 result_scale,则假定其为输入值的最高刻度。

此函数的工作速度明显慢于通常的 divide。如果不需要控制结果精度和/或需要快速计算,请考虑使用 divide

语法

divideDecimal(a, b[, result_scale])

参数

返回值

示例

┌─divideDecimal(toDecimal256(-12, 0), toDecimal32(2.1, 1), 10)─┐
│ -5.7142857142 │
└──────────────────────────────────────────────────────────────┘

与普通除法的区别

SELECT toDecimal64(-12, 1) / toDecimal32(2.1, 1);
SELECT toDecimal64(-12, 1) as a, toDecimal32(2.1, 1) as b, divideDecimal(a, b, 1), divideDecimal(a, b, 5);

结果

┌─divide(toDecimal64(-12, 1), toDecimal32(2.1, 1))─┐
│ -5.7 │
└──────────────────────────────────────────────────┘

┌───a─┬───b─┬─divideDecimal(toDecimal64(-12, 1), toDecimal32(2.1, 1), 1)─┬─divideDecimal(toDecimal64(-12, 1), toDecimal32(2.1, 1), 5)─┐
│ -12 │ 2.1 │ -5.7 │ -5.71428 │
└─────┴─────┴────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘
SELECT toDecimal64(-12, 0) / toDecimal32(2.1, 1);
SELECT toDecimal64(-12, 0) as a, toDecimal32(2.1, 1) as b, divideDecimal(a, b, 1), divideDecimal(a, b, 5);

结果

DB::Exception: Decimal result's scale is less than argument's one: While processing toDecimal64(-12, 0) / toDecimal32(2.1, 1). (ARGUMENT_OUT_OF_BOUND)

┌───a─┬───b─┬─divideDecimal(toDecimal64(-12, 0), toDecimal32(2.1, 1), 1)─┬─divideDecimal(toDecimal64(-12, 0), toDecimal32(2.1, 1), 5)─┐
│ -12 │ 2.1 │ -5.7 │ -5.71428 │
└─────┴─────┴────────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────────┘

byteSwap

反转整数的字节,即更改其 字节序

语法

byteSwap(a)

示例

byteSwap(3351772109)

结果

┌─byteSwap(3351772109)─┐
│ 3455829959 │
└──────────────────────┘

以上示例可以按以下方式计算

  1. 将十进制整数转换为其等效的大端序十六进制格式,即 3351772109 -> C7 C7 FB CD (4 字节)
  2. 反转字节,即 C7 C7 FB CD -> CD FB C7 C7
  3. 假设大端序,将结果转换回整数,即 CD FB C7 C7 -> 3455829959

此函数的一个用例是反转 IPv4

┌─toIPv4(byteSwap(toUInt32(toIPv4('205.251.199.199'))))─┐
│ 199.199.251.205 │
└───────────────────────────────────────────────────────┘