这很容易,但我们还远远没有解决整个问题。获胜的行程实际上是什么样子的?在这一点上,我们需要引入数组。让我们只从问题的一部分开始,加入每一跳的出发时间。
SELECT Carrier, TailNum,
groupArray(DepTime) as Departures,
length(groupArray(DepTime)) as Hops
FROM ontime
WHERE (FlightDate = toDate('2017-01-15')) AND (DepTime < ArrTime)
GROUP BY Carrier, TailNum
ORDER BY Hops DESC, Carrier, TailNum
LIMIT 5
/* sql answer*/
┌─Carrier─┬─TailNum─┬─Departures───────────────────────────┬─Hops─┐
│ HA │ N488HA │ [1157,1813,1921,1042,658,544,170...] │ 14 │
│ HA │ N492HA │ [718,824,938,1512,1622,1056,1743...] │ 14 │
│ HA │ N493HA │ [627,728,1012,1647,1801,904,1523...] │ 14 │
│ HA │ N483HA │ [845,725,1800,1904,1259,1407,113...] │ 12 │
│ HA │ N489HA │ [2047,1936,1031,1602,1438,1256,9...] │ 12 │
└─────────┴─────────┴──────────────────────────────────────┴──────┘
这个查询引入了groupArray(),它是一个聚合函数。
它收集每个GROUP BY子集的值,并按照处理行的顺序将它们添加到数组中。如果你在不同的列上调用groupArray(),它将为每个列创建一个数组。最重要的是,生成的数组将始终是相同的大小,并且有相同的顺序。换句话说,groupArray()是我们在上一篇博客文章中学习的ARRAY JOIN操作符的逆向操作(这句话很重要:说白了 → 一个是列转行,一个是行转列)
构建飞行路径的工作比较多。首先,我们只有出发时间,没有机场。第二,出发时间没有被排序。 让我们在下一个例子中解决这个问题,它增加了更多的数组,并按出发时间顺序进行排序:
SELECT Carrier, TailNum,
arraySort(groupArray(DepTime)) as Departures,
arraySort((x,y) -> y, groupArray(Origin), groupArray(DepTime)) as Origins,
length(groupArray(DepTime)) as Hops
FROM ontime WHERE (FlightDate = toDate('2017-01-15')) AND (DepTime < ArrTime)
GROUP BY Carrier, TailNum
ORDER BY Hops DESC, Carrier, TailNum
LIMIT 5 \G
/* sql answer*/
Row 1:
──────
Carrier: HA
TailNum: N488HA
Departures: [544,658,818,930,1042,1157,1322,1443,1556,1708,1813,1921,2025,2126]
Origins: ['HNL','KOA','HNL','LIH','OGG','LIH','HNL','OGG','LIH','OGG','HNL','OGG','HNL','OGG']
Hops: 14
...
如上面所示,我们依靠的是一个新的、非常通用的函数:arraySort()。
前面的查询说明了它的不同使用方法。在最简单的形式下,arraySort()接收一个数组参数并返回排序后的值。下面是一个例子。
SELECT arraySort([1224, 1923, 1003, 745]) AS s
/* sql answer*/
┌─s────────────────────┐
│ [745,1003,1224,1923] │
└──────────────────────┘
我们可以通过添加一个lambda表达式来使事情变得更加有趣,该表达式指示arraySort如何处理它遇到的每个数组值。
如果存在的话,lambda表达式总是第一个参数。下面的例子使用一个lambda表达式来扭转排序顺序。这个lambda表达式被应用于每个连续的数组值,ClickHouse使用所得到的值作为数组中的值的排序键。
SELECT arraySort(x -> (-x), [1224, 1923, 1003, 745]) AS s
/* sql answer*/
┌─s────────────────────┐
│ [1923,1224,1003,745] │
└──────────────────────┘
lambda并不总是必要的。你可以使用另外一种方法:arrayReverseSort()。下面的查询返回完全相同的答案:
SELECT arrayReverseSort([1224, 1923, 1003, 745]) AS s
最后,我们可以完全添加一个不同的键(另外一个是指定顺序的键。可以理解另类的排序键)。下面的例子有两个数组,用一个lambda表达式来挑选第二个数组作为排序键。ClickHouse将使用第二个数组的值作为键对第一个数组进行排序。
SELECT
arraySort((x, y) -> y, [1224, 1923, 1003, 745], [2, 1, 3, 4]) AS s
/* sql answer*/
┌─s────────────────────┐
│ [1923,1224,1003,745] │
└──────────────────────┘