跳到主要内容
跳到主要内容

Tuple(T1, T2, ...)

一个由多个元素组成的元组,每个元素都有各自的类型。元组必须至少包含一个元素。

元组用于对列进行临时分组。在查询中使用 IN 表达式时可以对列进行分组,也可用于指定 lambda 函数的某些形式参数。更多信息请参阅 IN 运算符高阶函数 章节。

元组可以作为查询结果返回。在这种情况下,对于除 JSON 以外的文本格式,值会以逗号分隔并包裹在圆括号中。在 JSON 格式中,元组会以数组形式输出(使用方括号)。

创建元组

你可以使用函数创建元组:

tuple(T1, T2, ...)

创建元组的示例:

SELECT tuple(1, 'a') AS x, toTypeName(x)
┌─x───────┬─toTypeName(tuple(1, 'a'))─┐
│ (1,'a') │ Tuple(UInt8, String)      │
└─────────┴───────────────────────────┘

一个元组(Tuple)可以只包含一个元素

示例:

SELECT tuple('a') AS x;
┌─x─────┐
│ ('a') │
└───────┘

语法 (tuple_element1, tuple_element2) 可用于在不调用 tuple() 函数的情况下创建一个包含多个元素的元组。

示例:

SELECT (1, 'a') AS x, (today(), rand(), 'someString') AS y, ('a') AS not_a_tuple;
┌─x───────┬─y──────────────────────────────────────┬─not_a_tuple─┐
│ (1,'a') │ ('2022-09-21',2006973416,'someString') │ a           │
└─────────┴────────────────────────────────────────┴─────────────┘

数据类型检测

在动态创建 tuple 时,ClickHouse 会将 tuple 参数的类型推断为能够容纳给定参数值的最小类型。 如果该值为 NULL,则推断出的类型为 Nullable

自动数据类型检测示例:

SELECT tuple(1, NULL) AS x, toTypeName(x)
┌─x─────────┬─toTypeName(tuple(1, NULL))──────┐
│ (1, NULL) │ Tuple(UInt8, Nullable(Nothing)) │
└───────────┴─────────────────────────────────┘

引用 Tuple 元素

Tuple 元素可以通过名称或索引进行引用:

CREATE TABLE named_tuples (`a` Tuple(s String, i Int64)) ENGINE = Memory;
INSERT INTO named_tuples VALUES (('y', 10)), (('x',-10));

SELECT a.s FROM named_tuples; -- 按名称访问
SELECT a.2 FROM named_tuples; -- 按索引访问

结果:

┌─a.s─┐
│ y   │
│ x   │
└─────┘

┌─tupleElement(a, 2)─┐
│                 10 │
│                -10 │
└────────────────────┘

使用 Tuple 的比较操作

两个 Tuple 的比较是通过从左到右依次比较它们的元素来完成的。若第一个 Tuple 的某个元素大于(小于)第二个 Tuple 中对应的元素,则认为第一个 Tuple 大于(小于)第二个 Tuple;否则(当这两个元素相等时),继续比较下一个元素。

示例:

SELECT (1, 'z') > (1, 'a') c1, (2022, 01, 02) > (2023, 04, 02) c2, (1,2,3) = (3,2,1) c3;
┌─c1─┬─c2─┬─c3─┐
│  1 │  0 │  0 │
└────┴────┴────┘

实际案例:

CREATE TABLE test
(
    `year` Int16,
    `month` Int8,
    `day` Int8
)
ENGINE = Memory AS
SELECT *
FROM values((2022, 12, 31), (2000, 1, 1));

SELECT * FROM test;

┌─year─┬─month─┬─day─┐
│ 2022 │    12 │  31 │
│ 2000 │     1 │   1 │
└──────┴───────┴─────┘

SELECT *
FROM test
WHERE (year, month, day) > (2010, 1, 1);

┌─year─┬─month─┬─day─┐
│ 2022 │    12 │  31 │
└──────┴───────┴─────┘
CREATE TABLE test
(
    `key` Int64,
    `duration` UInt32,
    `value` Float64
)
ENGINE = Memory AS
SELECT *
FROM values((1, 42, 66.5), (1, 42, 70), (2, 1, 10), (2, 2, 0));

SELECT * FROM test;

┌─key─┬─duration─┬─value─┐
│   1 │       42 │  66.5 │
│   1 │       42 │    70 │
│   2 │        1 │    10 │
│   2 │        2 │     0 │
└─────┴──────────┴───────┘

-- 查找每个键中持续时间最大的值,如果持续时间相同,则选择数值最大的

SELECT
    key,
    max(duration),
    argMax(value, (duration, value))
FROM test
GROUP BY key
ORDER BY key ASC;

┌─key─┬─max(duration)─┬─argMax(value, tuple(duration, value))─┐
│   1 │            42 │                                    70 │
│   2 │             2 │                                     0 │
└─────┴───────────────┴───────────────────────────────────────┘