将Clickhouse数组返回为列

时间:2019-02-21 16:28:02

标签: sql clickhouse

Clickhouse是否有可能包含一对转换为列的数组的结果?

形成此结果:

┌─f1──┬f2───────┬f3─────────────┐
│ 'a' │ [1,2,3] │ ['x','y','z'] │
│ 'b' │ [4,5,6] │ ['x','y','z'] │
└─────┴─────────┴───────────────┘

至:

┌─f1──┬x──┬y──┬z──┐
│ 'a' │ 1 │ 2 │ 3 │
│ 'b' │ 4 │ 5 │ 6 │
└─────┴───┴───┴───┘

想法是不必重复每行的标题值。

在我的情况下,“标头”数组f3通过查询唯一并连接到f1,f2。

2 个答案:

答案 0 :(得分:2)

您可以借助indexOf函数来做到这一点。

SELECT *
FROM test_sof 

┌─f1─┬─f2──────┬─f3────────────┐
│ a  │ [1,2,3] │ ['x','y','z'] │
└────┴─────────┴───────────────┘
┌─f1─┬─f2────────┬─f3────────────────┐
│ c  │ [7,8,9,0] │ ['x','y','z','n'] │
└────┴───────────┴───────────────────┘
┌─f1─┬─f2─────────┬─f3────────────────┐
│ d  │ [7,8,9,11] │ ['x','y','z','n'] │
└────┴────────────┴───────────────────┘
┌─f1─┬─f2──────┬─f3────────────┐
│ b  │ [4,5,6] │ ['x','y','z'] │
└────┴─────────┴───────────────┘

4 rows in set. Elapsed: 0.001 sec.

然后:

SELECT 
    f1, 
    f2[indexOf(f3, 'x')] AS x, 
    f2[indexOf(f3, 'y')] AS y, 
    f2[indexOf(f3, 'z')] AS z, 
    f2[indexOf(f3, 'n')] AS n
FROM test_sof 
ORDER BY 
    f1 ASC, 
    x ASC

┌─f1─┬─x─┬─y─┬─z─┬──n─┐
│ a  │ 1 │ 2 │ 3 │  0 │
│ b  │ 4 │ 5 │ 6 │  0 │
│ c  │ 7 │ 8 │ 9 │  0 │
│ d  │ 7 │ 8 │ 9 │ 11 │
└────┴───┴───┴───┴────┘

4 rows in set. Elapsed: 0.002 sec. 

请记住当数据数组中不存在标头数组的索引或反之时的情况。

UPD :在不知道“标题”的情况下获取数据的方式。

您将获得三列,第三列带有标题。

SELECT 
    f1, 
    f2[num] AS f2_el, 
    f3[num] AS f3_el
FROM test_sof 
ARRAY JOIN arrayEnumerate(f2) AS num
ORDER BY f1 ASC

┌─f1─┬─f2_el─┬─f3_el─┐
│ a  │     1 │ x     │
│ a  │     2 │ y     │
│ a  │     3 │ z     │
│ b  │     4 │ x     │
│ b  │     5 │ y     │
│ b  │     6 │ z     │
│ c  │     7 │ x     │
│ c  │     8 │ y     │
│ c  │     9 │ z     │
│ c  │     0 │ n     │
│ d  │     7 │ x     │
│ d  │     8 │ y     │
│ d  │     9 │ z     │
│ d  │    11 │ n     │
└────┴───────┴───────┘

14 rows in set. Elapsed: 0.006 sec.

答案 1 :(得分:0)

这是一个有趣的难题。正如已经指出的那样,indexOf()函数似乎是在ClickHouse中旋转数组列的最佳方法,但需要显式选择数组位置。如果您使用的是Python,而结果集不是那么大,则可以通过将数组值翻转到SQL中的行,然后在Python中旋转f2和f3列,以更一般的方式解决问题。运作方式如下。

首先,使用clickHouse-sqlalchemy和pandas将匹配的数组扩展为以下行。 (此示例使用在Anaconda上运行的Jupyter Notebook。)

# Load SQL Alchemy and connect to ClickHouse
from sqlalchemy import create_engine
%load_ext sql
%sql clickhouse://default:@localhost/default

# Use JOIN ARRAY to flip corresponding positions in f2, f3 to rows.
result = %sql select * from f array join f2, f3
df = result.DataFrame()
print(df)

数据框显示如下:

  f1  f2 f3
0  a   1  x
1  a   2  y
2  a   3  z
3  b   4  x
4  b   5  y
5  b   6  z

现在,我们可以将f2和f3转换为新的数据帧。

dfp = df.pivot(columns='f3', values='f2', index='f1')
print(dfp)

新数据框dfp出现如下:

f3  x  y  z
f1         
a   1  2  3
b   4  5  6

此解决方案要求您在数据库外部工作,但具有的优点是,只要名称和值匹配,它通常可用于任何一组数组。例如,如果我们添加另一行具有不同的值和属性,则相同的代码将获得正确的答案。这是新的一行。

insert into f values ('c', [7,8,9,10], ['x', 'y', 'aa', 'bb'])

数据透视图框将显示如下。 NaN对应缺失值。

f3   aa    bb    x    y    z
f1                          
a   NaN   NaN  1.0  2.0  3.0
b   NaN   NaN  4.0  5.0  6.0
c   9.0  10.0  7.0  8.0  NaN

有关此解决方案的更多信息,请参见https://pandas.pydata.org/pandas-docs/stable/getting_started/dsintro.htmlhttps://github.com/xzkostyan/clickhouse-sqlalchemy