【问题标题】:Return clickhouse array as column将 clickhouse 数组作为列返回
【发布时间】:2019-07-15 15:38:43
【问题描述】:

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 │
└─────┴───┴───┴───┘

这个想法是不必为每一行重复标题值。

在我的例子中,“header”数组 f3 由查询唯一并连接到 f1,f2。

【问题讨论】:

    标签: sql clickhouse


    【解决方案1】:

    你可以在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.
    

    【讨论】:

    • 这是我实施的解决方案,但在我的情况下,它需要第一个请求才能找到数组标头。但由于我有数组,我可以避免 indexOf 并直接使用索引。尽管这是一个可行的解决方案,但我认为它不是理想的“完整的 clickhouse”解决方案。
    • 好的,我现在知道你的问题了。我想稍后更新我的答案,因为我还记得另一种方式
    • 但是如果你想将你的“标题”拆分为结果集中的列,你必须知道所有这些,否则是不可能的。方式,如何在不请求标题的情况下执行此操作将返回标题作为“标题行”的值
    • “不可能”是一个有效的答案。
    【解决方案2】:

    这是一个有趣的谜题。正如已经指出的那样, 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

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 2019-11-04
      • 2020-12-29
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-23
      相关资源
      最近更新 更多