【问题标题】:Record ranking in ClickhouseClickhouse中的记录排名
【发布时间】:2020-05-14 09:34:19
【问题描述】:

例如,我有一张桌子:

CREATE DATABASE IF NOT EXISTS example;
CREATE TABLE IF NOT EXISTS example.etable (starttime datetime, name string,) ENGINE = MergeTree; 

为了应用 GROUP BY 操作,我需要计算每条记录的排名,以便“名称”字段值相同的连续有序记录具有相同的排名。如果当前记录的 name 字段的值不是上一个,则排名递增。

在 MySQL 中,这可以通过这样的查询来完成:

SELECT name, starttime, 
    @prev := @curr,
    @curr := name,
    @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
FROM example.etable,
    (SELECT @curr := null, @prev := null, @rank := 0) r
ORDER BY starttime ASC;

示例输出:

+------+---------------------+----------------+---------------+------+
| name | starttime           | @prev := @curr | @curr := name | rank |
+------+---------------------+----------------+---------------+------+
| s1   | 2020-05-14 15:56:46 | NULL           | s1            | 1    |
| s1   | 2020-05-14 15:56:49 | s1             | s1            | 1    |
| s1   | 2020-05-14 15:56:51 | s1             | s1            | 1    |
| s2   | 2020-05-14 15:56:53 | s1             | s2            | 2    |
| s1   | 2020-05-14 15:56:56 | s2             | s1            | 3    |
| s3   | 2020-05-14 15:56:59 | s1             | s3            | 4    |
+------+---------------------+----------------+---------------+------+

那么,问题来了,如何在 Clickhouse 中实现这一点?

【问题讨论】:

    标签: clickhouse


    【解决方案1】:

    计算排名包括三个步骤:

    • 将关系转换为数组 (groupArray)
    • 计算等级 (arrayCumSum)
    • 将数组转换为关系 (arrayJoin)。
    SELECT result.1 starttime, result.2 name, result.3 rank
    FROM (
        SELECT 
            groupArray(starttime) starttime_arr,
            groupArray(name) name_arr,
            arrayCumSum((name, index) -> index = 1 ? 1 : (name_arr[index - 1] = name ? 0 : 1), name_arr, arrayEnumerate(name_arr)) ranks,
            arrayZip(starttime_arr, name_arr, ranks) result_array,
            arrayJoin(result_array) result
        FROM (
            SELECT * 
            FROM (
                /* emulate the 'example.etable'-table */
                SELECT toDateTime(test_data.1) AS starttime, test_data.2 AS name
                FROM (
                    SELECT arrayJoin([
                        ('2020-05-14 15:56:46', 's1'),
                        ('2020-05-14 15:56:49', 's1'),
                        ('2020-05-14 15:56:51', 's1'),
                        ('2020-05-14 15:56:53', 's2'),
                        ('2020-05-14 15:56:56', 's1'),
                        ('2020-05-14 15:56:59', 's3')
                    ]) test_data))
            ORDER BY starttime)
        )
    
    /* result
    ┌───────────starttime─┬─name─┬─rank─┐
    │ 2020-05-14 15:56:46 │ s1   │    1 │
    │ 2020-05-14 15:56:49 │ s1   │    1 │
    │ 2020-05-14 15:56:51 │ s1   │    1 │
    │ 2020-05-14 15:56:53 │ s2   │    2 │
    │ 2020-05-14 15:56:56 │ s1   │    3 │
    │ 2020-05-14 15:56:59 │ s3   │    4 │
    └─────────────────────┴──────┴──────┘
    */
    

    【讨论】:

    • 谢谢!它有点复杂但有效!
    猜你喜欢
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 1970-01-01
    • 2018-12-27
    相关资源
    最近更新 更多