ClickHouse基于数据分析常用函数

文章标题

背景:基于初次接触数据分析,对ck函数的不熟悉,此文章主要基于ck特有的sql语法来做讲解;

官网:https://clickhouse.tech/docs/zh

一、WITH语法-定义变量

ClickHouse支持CTE(Common Table Expression,公共表达式),以增强查询语句的表达

sql 复制代码
SELECT pow(2, 2);

┌─pow(2, 2)─┐
│         4 │
└───────────┘

SELECT pow(pow(2, 2), 2);

┌─pow(pow(2, 2), 2)─┐
│                16 │
└───────────────────┘

在改用CTE的形式后,可以极大地提高语句的可读性和维护性。

sql 复制代码
WITH
   pow(2, 2) AS a
SELECT pow(a, 2);

┌─pow(a, 2)─┐
│        16 │
└───────────┘

1.1 定义变量

可以定义变量,这些变量能够在后续的查询子句中被直接访问。

sql 复制代码
# tb_mysql- 创建数据
DROP TABLE IF EXISTS tb_mysql;
CREATE TABLE tb_mysql (
        id UInt8,
        name String,
        age UInt8
)ENGINE = MergeTree()
ORDER BY id;
INSERT INTO tb_mysql VALUES ('1', 'tom', 23);
INSERT INTO tb_mysql VALUES ('2', 'lisa', 33);
INSERT INTO tb_mysql VALUES ('3', 'henry', 44);
INSERT INTO tb_mysql VALUES ('1', 'linda', 23);
INSERT INTO tb_mysql VALUES ('2', 'ross', 33);
INSERT INTO tb_mysql VALUES ('1', 'julie', 23);
INSERT INTO tb_mysql VALUES ('2', 'niki', 33);

# 数据分析
WITH 
    1  AS constant
SELECT
    id + constant,
    name
FROM
    tb_mysql;
    
┌─plus(id, constant)─┬─name─┐
│                  3 │ niki │
└────────────────────┴──────┘
┌─plus(id, constant)─┬─name──┐
│                  2 │ tom   │
│                  2 │ linda │
│                  2 │ julie │
│                  3 │ lisa  │
│                  3 │ ross  │
│                  4 │ henry │
└────────────────────┴───────┘

1.2 调用函数

可以访问SELECT子句中的列字段,并调用函数做进一步的加工处理

sql 复制代码
# tb_partition-创造数据
DROP TABLE IF EXISTS tb_partition;
CREATE TABLE tb_partition (
      id UInt8,
      name String,
      birthday String
)ENGINE = MergeTree()
ORDER BY id;
INSERT INTO tb_partition VALUES ('1', 'x1', '2024-05-20 10:50:46');
INSERT INTO tb_partition VALUES ('2', 'xy', '2024-05-20 11:17:47');
INSERT INTO tb_partition VALUES ('3', 'xf', '2024-05-19 11:11:12');


# 数据分析
WITH 
    toDate(birthday) AS bday
SELECT
    id,
    name,
    bday
FROM
    tb_partition;

┌─id─┬─name─┬───────bday─┐
│  1 │ x1   │ 2024-05-20 │
└────┴──────┴────────────┘
┌─id─┬─name─┬───────bday─┐
│  2 │ xy   │ 2024-05-20 │
└────┴──────┴────────────┘
┌─id─┬─name─┬───────bday─┐
│  3 │ xf   │ 2024-05-19 │
└────┴──────┴────────────┘

1.3 子查询

可以定义子查询,在WITH中使用子查询时有一点需要特别注意,该查询语句只能 返回一行数据,如果结果集的数据大于一行则会抛出异常;

sql 复制代码
WITH 
    (SELECT 
         *
     FROM 
         tb_partition
     WHERE tb_partition.id = '1') AS sub
SELECT
    * ,
    sub
FROM 
    tb_partition;

┌─id─┬─name─┬─birthday────────────┬─sub────────────────────────────┐
│  3 │ xf   │ 2024-05-19 11:11:12 │ (1,'x1','2024-05-20 10:50:46') │
└────┴──────┴─────────────────────┴────────────────────────────────┘
┌─id─┬─name─┬─birthday────────────┬─sub────────────────────────────┐
│  2 │ xy   │ 2024-05-20 11:17:47 │ (1,'x1','2024-05-20 10:50:46') │
└────┴──────┴─────────────────────┴────────────────────────────────┘
┌─id─┬─name─┬─birthday────────────┬─sub────────────────────────────┐
│  1 │ x1   │ 2024-05-20 10:50:46 │ (1,'x1','2024-05-20 10:50:46') │
└────┴──────┴─────────────────────┴────────────────────────────────┘

二、GROUP BY子句(结合WITH ROLLUP、CUBE、TOTALS)

  • ROLLUP:能够按照聚合键从右向左上卷数据,基于聚 合函数依次生成分组小计和总计。如果设聚合键的个数为n,则最终 会生成小计的个数为n+1
  • CUBE:像立方体模型一样,基于聚合键之间所有的 组合生成小计信息。如果设聚合键的个数为n,则最终小计组合的个 数为2的n次方。接下来用示例说明它的用法
  • TOTALS:会基于聚合函数对所有数据进行总计
sql 复制代码
# tb_with-创建数据
DROP TABLE IF EXISTS tb_with;
CREATE TABLE tb_with (
    id UInt8,
    vist UInt8,
    province String,
    city String,
    area String
)ENGINE = MergeTree()
ORDER BY id;
INSERT INTO tb_with VALUES (1, 12 ,'湖北', '黄冈', '武穴');
INSERT INTO tb_with VALUES (2, 12 ,'湖北', '黄冈', '黄州');
INSERT INTO tb_with VALUES (3, 12 ,'湖北', '黄冈', '麻城');
INSERT INTO tb_with VALUES (4, 32 ,'湖北', '黄冈', '黄梅');
INSERT INTO tb_with VALUES (5, 12 ,'湖北', '黄石', '下陆');
INSERT INTO tb_with VALUES (6, 54 ,'湖北', '黄石', '铁山');
INSERT INTO tb_with VALUES (7, 12 ,'湖北', '黄石', '石灰窑');
INSERT INTO tb_with VALUES (8, 89 ,'湖北', '荆州', '荆门');
INSERT INTO tb_with VALUES (9, 99 ,'湖北', '荆州', '钟祥');


# 数据分析
SELECT 
    province,
    city,
    area,
    sum(vist) AS total_visit
FROM tb_with
GROUP BY province, city, area WITH ROLLUP ;

┌─province─┬─city─┬─area───┬─total_visit─┐
│ 湖北     │ 黄冈 │ 黄梅   │          32 │
│ 湖北     │ 荆州 │ 钟祥   │          99 │
│ 湖北     │ 黄冈 │ 麻城   │          12 │
│ 湖北     │ 荆州 │ 荆门   │          89 │
│ 湖北     │ 黄冈 │ 黄州   │          12 │
│ 湖北     │ 黄石 │ 下陆   │          12 │
│ 湖北     │ 黄石 │ 石灰窑 │          12 │
│ 湖北     │ 黄石 │ 铁山   │          54 │
│ 湖北     │ 黄冈 │ 武穴   │          12 │
└──────────┴──────┴────────┴─────────────┘
┌─province─┬─city─┬─area─┬─total_visit─┐
│ 湖北     │ 黄石 │      │          78 │
│ 湖北     │ 荆州 │      │         188 │
│ 湖北     │ 黄冈 │      │          68 │
└──────────┴──────┴──────┴─────────────┘
┌─province─┬─city─┬─area─┬─total_visit─┐
│ 湖北     │      │      │         334 │
└──────────┴──────┴──────┴─────────────┘
┌─province─┬─city─┬─area─┬─total_visit─┐
│          │      │      │         334 │
└──────────┴──────┴──────┴─────────────┘

三、FORM语法

SQL是一种面向集合的编程语言,from决定了程序从那里读取数据

  1. 表中查询数据
  2. 子查询中查询数据
  3. 表函数中查询数据 select * from numbers(3)

3.1表函数

构建表的函数,使用场景如下:

SELECT查询的(FROM)子句

创建表 AS 查询

3.1.1 file

sql 复制代码
-- 数据文件必须在指定的目录下 /var/lib/clickhouse/user_files

SELECT 
	*
FROM file('demo.csv', 'CSV', 'id Int8,name String, age UInt8')
-- 文件夹下任意的文件
SELECT
	*
FROM file('*', 'CSV', 'id Int8, name String, age UInt8')

3.1.2 numbers

sql 复制代码
-- numbers(N) -- 返回一个包含单个 'number' 列(UInt64)的表,其中包含从0到N-1的整数。
-- numbers(N, M) - 返回一个包含单个 'number' 列(UInt64)的表,其中包含从N到(N+M-1)的整数。
SELECT 
	*
FROM 
	numbers(10);

SELECT 
	*
FROM 
	numbers(2, 10);

SELECT 
	*
FROM 
	numbers(2, 10) 
LIMIT 3;

SELECT 
	toDate('2020-01-01') + number AS d
FROM 
numbers(365);

3.1.3 mysql

sql 复制代码
-- CH可以直接从mysql服务中查询数据
mysql('host:port', 'database', 'table', 'user', 'password'[, replace_query, 'on_duplicate_clause']);

SELECT
	*
FROM 
	mysql('linux01:3306', 'db_doit_ch', 'emp', 'root', 'root');

3.1.4 hdfs

sql 复制代码
SELECT 
	*
FROM
	hdfs('hdfs://hdfs1:9000/test', 'TSV', 'column1 UInt32, column2 UInt32') 
LIMIT 2;


SELECT
	*
FROM
	hdfs('hdfs://linux01:8020/demo.csv', 'CSV', 'id Int8, name String, age Int8')

四、ARRAY JOIN语法(区别于arrayJoin(arr)函数)

ARRAY JOIN子句允许在数据表的内部,与数组或嵌套类型的字段进行JOIN操作,从而将一行数组展开为多行,类似于hive中的explode炸裂函数的功能

sql 复制代码
# ARRAY JOIN-创建数据
DROP TABLE IF EXISTS tb_array_join;
CREATE TABLE tb_array_join (
    id Int8,
    hobby Array(String)
)ENGINE = Log;

INSERT INTO tb_array_join VALUES (1, ['eat', 'drink', 'sleep']), (2, ['study', 'sport', 'read']), (2, ['study', 'sport']);

# 查询数据
SELECT * FROM tb_array_join;
┌─id─┬─hobby────────────────────┐
│  1 │ ['eat','drink','sleep']  │
│  2 │ ['study','sport','read'] │
│  2 │ ['study','sport']        │
└────┴──────────────────────────┘

# 分析1
SELECT
	id,
	hobby,
	hobby_expand
FROM
	tb_array_join
ARRAY JOIN
hobby AS hobby_expand;
┌─id─┬─hobby────────────────────┬─hobby_expand─┐
│  1 │ ['eat','drink','sleep']  │ eat          │
│  1 │ ['eat','drink','sleep']  │ drink        │
│  1 │ ['eat','drink','sleep']  │ sleep        │
│  2 │ ['study','sport','read'] │ study        │
│  2 │ ['study','sport','read'] │ sport        │
│  2 │ ['study','sport','read'] │ read         │
│  2 │ ['study','sport']        │ study        │
│  2 │ ['study','sport']        │ sport        │
└────┴──────────────────────────┴──────────────┘

# 分析2
SELECT
	id,
	hobby,
	arrayEnumerate(hobby) AS indexs
FROM
	tb_array_join;
┌─id─┬─hobby────────────────────┬─indexs──┐
│  1 │ ['eat','drink','sleep']  │ [1,2,3] │
│  2 │ ['study','sport','read'] │ [1,2,3] │
│  2 │ ['study','sport']        │ [1,2]   │
└────┴──────────────────────────┴─────────┘

# 分析3(将hobby展开,并与索引组成一列)
SELECT
	id,
	hobby_expand,
	index
FROM
	tb_array_join
ARRAY JOIN
hobby AS hobby_expand,
arrayEnumerate(hobby) AS index;

┌─id─┬─hobby_expand─┬─index─┐
│  1 │ eat          │     1 │
│  1 │ drink        │     2 │
│  1 │ sleep        │     3 │
│  2 │ study        │     1 │
│  2 │ sport        │     2 │
│  2 │ read         │     3 │
│  2 │ study        │     1 │
│  2 │ sport        │     2 │
└────┴──────────────┴───────┘

五、连续销售案例

需求:对如下样本数据求每个店铺最高连续n天的销售情况

sql 复制代码
# tb_shop-创建数据
# 思路:
# 1、按照name和cdate排序;
# 2、对name和cdate相同的数据只保留一个,按此业务所以保留每天最大的营销额
# 基于上述需求,所以用ReplacingMergeTree引擎实现
# 3、然后基于下方的分析步骤进行逐步分析
DROP TABLE IF EXISTS tb_shop;
CREATE TABLE tb_shop (
        name String,
        cdate Date,
        cost Float64
)ENGINE = ReplacingMergeTree()
ORDER BY (name, cdate);
INSERT INTO tb_shop VALUES ('a', '2024-02-05', 200),
('a', '2024-02-04', 320),
('a', '2024-02-03', 260),
('a', '2024-01-29', 300),
('a', '2024-01-29', 230),
('a', '2024-01-28', 880),
('a', '2024-01-27', 900),
('a', '2024-01-26', 350),
('a', '2024-01-26', 500),
('a', '2024-01-26', 900),

('b', '2024-02-05', 200),
('b', '2024-02-04', 320),
('b', '2024-02-03', 260),
('b', '2024-02-02', 670),

('c', '2024-02-05', 200),
('c', '2024-02-05', 900),
('c', '2024-02-05', 800),
('c', '2024-02-05', 200);

# 按照以下sql一步步排查
# 分析1
SELECT 
	name,
	groupArray(cdate) AS arr
FROM
	tb_shop
GROUP BY name;
┌─name─┬─arr──────────────────────────────────────────────────────────────────────────────────────────┐
│ b    │ ['2024-02-02','2024-02-03','2024-02-04','2024-02-05']                                        │
│ c    │ ['2024-02-05']                                                                               │
│ a    │ ['2024-01-26','2024-01-27','2024-01-28','2024-01-29','2024-02-03','2024-02-04','2024-02-05'] │
└──────┴──────────────────────────────────────────────────────────────────────────────────────────────┘

# 分析2
SELECT
    name,
    ct,
    arr_index
FROM
    (
        SELECT
            name,
            groupArray(cdate) AS arr,
            arrayEnumerate(arr) AS idx
        FROM
            tb_shop
        GROUP BY name
    )
ARRAY JOIN
arr AS ct,
idx AS arr_index;
┌─name─┬─────────ct─┬─arr_index─┐
│ b    │ 2024-02-02 │         1 │
│ b    │ 2024-02-03 │         2 │
│ b    │ 2024-02-04 │         3 │
│ b    │ 2024-02-05 │         4 │
│ c    │ 2024-02-05 │         1 │
│ a    │ 2024-01-26 │         1 │
│ a    │ 2024-01-27 │         2 │
│ a    │ 2024-01-28 │         3 │
│ a    │ 2024-01-29 │         4 │
│ a    │ 2024-02-03 │         5 │
│ a    │ 2024-02-04 │         6 │
│ a    │ 2024-02-05 │         7 │
└──────┴────────────┴───────────┘

# 分析3
SELECT
    name,
    (ct - arr_index) AS diff
FROM
    (
        SELECT
            name,
            groupArray(cdate) AS arr,
            arrayEnumerate(arr) AS idx
        FROM
            tb_shop
        GROUP BY name
    )
ARRAY JOIN
arr AS ct,
idx AS arr_index;
┌─name─┬───────diff─┐
│ b    │ 2024-02-01 │
│ b    │ 2024-02-01 │
│ b    │ 2024-02-01 │
│ b    │ 2024-02-01 │
│ c    │ 2024-02-04 │
│ a    │ 2024-01-25 │
│ a    │ 2024-01-25 │
│ a    │ 2024-01-25 │
│ a    │ 2024-01-25 │
│ a    │ 2024-01-29 │
│ a    │ 2024-01-29 │
│ a    │ 2024-01-29 │
└──────┴────────────┘

# 分析4
SELECT
    name,
    (ct - arr_index) AS diff,
    count(1)
FROM
    (
        SELECT
            name,
            groupArray(cdate) AS arr,
            arrayEnumerate(arr) AS idx
        FROM
            tb_shop
        GROUP BY name
    )
ARRAY JOIN
arr AS ct,
idx AS arr_index
GROUP BY name, diff;
┌─name─┬───────diff─┬─count()─┐
│ c    │ 2024-02-04 │       1 │
│ a    │ 2024-01-25 │       4 │
│ b    │ 2024-02-01 │       4 │
│ a    │ 2024-01-29 │       3 │
└──────┴────────────┴─────────┘
# 分析5
SELECT
    name,
    (ct - arr_index) AS diff,
    count(1) AS cc
FROM
    (
        SELECT
            name,
            groupArray(cdate) AS arr,
            arrayEnumerate(arr) AS idx
        FROM
            tb_shop
        GROUP BY name
    )
ARRAY JOIN
arr AS ct,
idx AS arr_index
GROUP BY name, diff
ORDER BY name, cc DESC;
┌─name─┬───────diff─┬─cc─┐
│ a    │ 2024-01-25 │  4 │
│ a    │ 2024-01-29 │  3 │
│ b    │ 2024-02-01 │  4 │
│ c    │ 2024-02-04 │  1 │
└──────┴────────────┴────┘

# 分析6
SELECT
    name,
    (ct - arr_index) AS diff,
    count(1) AS cc
FROM
    (
        SELECT
            name,
            groupArray(cdate) AS arr,
            arrayEnumerate(arr) AS idx
        FROM
            tb_shop
        GROUP BY name
    )
ARRAY JOIN
arr AS ct,
idx AS arr_index
GROUP BY name, diff
ORDER BY name, cc DESC
LIMIT 1 BY name;
┌─name─┬───────diff─┬─cc─┐
│ a    │ 2024-01-25 │  4 │
│ b    │ 2024-02-01 │  4 │
│ c    │ 2024-02-04 │  1 │
└──────┴────────────┴────┘

六、连接函数

6.1 连接精度

  • 连接精度决定了JOIN查询在连接数据时所使用的策略,目前支持ALL、ANY和ASOF三种类型。如果不主动声明,则默认是ALL。可以通过join_default_strictness配置参数修改默认的连接精度类型。
  • 对数据是否连接匹配的判断是通过JOIN KEY进行的,目前只支持等式(EQUAL JOIN)。交叉连接(CROSS JOIN)不需要使用JOIN KEY,因为它会产生笛卡尔积。
sql 复制代码
# 准备数据
DROP TABLE IF EXISTS yg;
CREATE TABLE yg(
 id Int8,
 name String,
 age UInt8,
 bid Int8
)ENGINE = Log;
INSERT INTO yg VALUES(1, 'AA', 23, 1),
(2, 'BB', 24, 3),
(3, 'VV', 27, 1),
(4, 'CC', 13, 3),
(5, 'KK', 53, 3),
(6, 'MM', 33, 3);

DROP TABLE IF EXISTS bm;
CREATE TABLE bm(
  bid Int8,
  name String
)ENGINE = Log;
INSERT INTO bm VALUES(1, 'x'),(2, 'Y'),(3, 'z');

DROP TABLE IF EXISTS gz;
CREATE TABLE gz(
  id Int8,
  jb Int64,
  jj Int64
)ENGINE = Log;
INSERT INTO gz VALUES(1, 1000, 2000),
(1, 1000, 2000),(2, 2000, 1233),(3, 2000, 3000),(4, 4000, 1000);

6.1.1 ALL

如果左表内的一行数据,在右表中有多行数据与之连接匹配,则返回右表中全部连接的数据。而判断连接匹配的依据是左表与右表内的数据,基于连接键(JOIN KEY)的取值完全相等(equals),等同于left.key = right.key

sql 复制代码
# 分析1
SELECT 
	*
FROM
	yg
ALL INNER JOIN gz ON yg.id = gz.id;
┌─id─┬─name─┬─age─┬─bid─┬─gz.id─┬───jb─┬───jj─┐
│  1 │ AA   │  23 │   1 │     1 │ 1000 │ 2000 │
│  1 │ AA   │  23 │   1 │     1 │ 1000 │ 2000 │
│  2 │ BB   │  24 │   3 │     2 │ 2000 │ 1233 │
│  3 │ VV   │  27 │   1 │     3 │ 2000 │ 3000 │
│  4 │ CC   │  13 │   3 │     4 │ 4000 │ 1000 │
└────┴──────┴─────┴─────┴───────┴──────┴──────┘

6.1.2 ANY

如果左表内的一行数据,在右表中有多行数据与之连接匹配,则返回右表中第一行连接的数据。ANY与ALL判断连接匹配的依据相同。

sql 复制代码
# 分析2
SELECT 
	*
FROM
	yg
ANY INNER JOIN gz ON yg.id = gz.id;
┌─id─┬─name─┬─age─┬─bid─┬─gz.id─┬───jb─┬───jj─┐
│  1 │ AA   │  23 │   1 │     1 │ 1000 │ 2000 │
│  2 │ BB   │  24 │   3 │     2 │ 2000 │ 1233 │
│  3 │ VV   │  27 │   1 │     3 │ 2000 │ 3000 │
│  4 │ CC   │  13 │   3 │     4 │ 4000 │ 1000 │
└────┴──────┴─────┴─────┴───────┴──────┴──────┘

6.1.3 ASOF

ASOF连接键之后追加定义一个模糊连接的匹配条件ASOF_COLUMN。

sql 复制代码
DROP TABLE IF EXISTS emp1;
CREATE TABLE emp1(
   id Int8,
   name String,
   ctime DateTime
)ENGINE = Log;
INSERT INTO emp1 VALUES(1, 'AA', '2021-01-03 00:00:00'),(1, 'AA', '2021-01-02 00:00:00'),(2, 'CC', '2021-01-01 00:00:00'),(3, 'DD', '2021-01-01 00:00:00'),(4, 'EE', '2021-01-01 00:00:00');

DROP TABLE IF EXISTS emp2;
CREATE TABLE emp2(
  id Int8,
  name String,
  ctime DateTime
)ENGINE = Log;
INSERT INTO emp2 VALUES (1, 'aa', '2021-01-02 00:00:00'),(1, 'aa', '2021-01-02 00:00:00'),(2, 'cc', '2021-01-02 00:00:00'),(3, 'dd', '2021-01-02 00:00:00');

# 分析
SELECT 
*
FROM emp1
ASOF INNER JOIN emp2
ON (emp1.id = emp2.id) AND (emp1.ctime > emp2.ctime);
┌─id─┬─name─┬───────────────ctime─┬─emp2.id─┬─emp2.name─┬──────────emp2.ctime─┐
│  1 │ AA   │ 2021-01-03 00:00:00 │       1 │ aa        │ 2021-01-02 00:00:00 │
└────┴──────┴─────────────────────┴─────────┴───────────┴─────────────────────┘

七、系统函数介绍

ClickHouse主要提供两类函数-普通函数和聚合函数。普通函数由IFunction接口定义,拥有数十种函数实现,例如FunctionFormationDateTime、FunctionSubstring等。除了一些常见的函数(诸如四则运算、日期转换等之外),也不乏一些非常实用的函数,例如网址提取函数、IP地址脱敏函数等。普通函数是没有状态的,函数效果作用于每行数据之上。当然,在函数具体执行的过程中,并不会一行一行地运算,而是采用向量化的方式直接作用于一整列数据。聚合函数由IAggregateFunction接口定义,相比于无状态的普通函数,聚合函数是有状态的。以COUNT聚合函数为例,其AggregateFunctionCount的状态使用整UInt64记录。聚合函数的状态支持序列化与反序列话,所以能够在分布式节点之间进行传输,以实现增量计算。

  • 普通函数
    • 类型转换函数
    • 日期函数
    • 条件函数
    • 数组函数
    • 字符串函数
    • json解析函数
  • 高阶函数
  • 聚合函数
  • 表函数
    ps:详情见官网

八、JSON解析案例

sql 复制代码
-- 建表
DROP TABLE IF EXISTS tb_ods_log;
CREATE TABLE tb_ods_log (
    line String
) ENGINE = Log;

INSERT INTO tb_ods_log VALUES('{"account":"14d9TM","deviceId":"Kcjksekjg","ip":"180.12.12.3","sessionId":"sfjkeIGj","eventId":"","properties":{"adId":"6","adCampain":"7"},"timeStamp":18992891918}'),
                           ('{"account":"14d9TM","deviceId":"Kcfafafkjg","ip":"180.12.12.3","sessionId":"sfjkeIGj","eventId":"","properties":{"adId":"6","adCampain":"7"},"timeStamp":189923891918}'),
                           ('{"account":"14faTM","deviceId":"Kcfaekjg","ip":"180.12.12.3","sessionId":"sfjkeIGj","eventId":"","properties":{"adId":"6","adCampain":"5"},"timeStamp":189924891918}');

# json解析
WITH 
  visitParamExtractString(line, 'account') as account,
  visitParamExtractString(line, 'deviceId') as deviceId,
  visitParamExtractString(line, 'sessionId') as sessionId,
  visitParamExtractRaw(line, 'properties') as properties,
  visitParamExtractInt(line, 'timeStamp') as timeStamp
SELECT
	account,
	deviceId,
	sessionId,
	properties,
	timeStamp
FROM
    tb_ods_log 
LIMIT 10;

┌─account─┬─deviceId───┬─sessionId─┬─properties───────────────────┬────timeStamp─┐
│ 14d9TM  │ Kcjksekjg  │ sfjkeIGj  │ {"adId":"6","adCampain":"7"} │  18992891918 │
│ 14d9TM  │ Kcfafafkjg │ sfjkeIGj  │ {"adId":"6","adCampain":"7"} │ 189923891918 │
│ 14faTM  │ Kcfaekjg   │ sfjkeIGj  │ {"adId":"6","adCampain":"5"} │ 189924891918 │
└─────────┴────────────┴───────────┴──────────────────────────────┴──────────────┘

九、实用函数

在进行数据分析的时,通常会设计到计算或者类型转换;在进行此处理过程中会出现类型不兼容的情况,而此时就可以通过toTypeName(name)函数来打印某一变量的类型进行排查。

sql 复制代码
SELECT
    1 AS b,
    toTypeName(b)
    
┌─b─┬─toTypeName(1)─┐
│ 1 │ UInt8         │
└───┴───────────────┘

十、语法注意事项

  • cklickhouse大小写敏感
  • 实现需求的时候可以先查找ck是否有函数可以支持,如果不支持再去想其他方式

课件学习地址

相关推荐
不知几秋3 小时前
sqlilab-Less-18
sql
Amctwd4 小时前
【SQL】如何在 SQL 中统计结构化字符串的特征频率
数据库·sql
莫叫石榴姐4 小时前
大模型在数据分析领域的研究综述
大数据·数据挖掘·数据分析
小白学大数据9 小时前
Scrapy框架下地图爬虫的进度监控与优化策略
开发语言·爬虫·python·scrapy·数据分析
lqlj223310 小时前
Spark SQL 读取 CSV 文件,并将数据写入 MySQL 数据库
数据库·sql·spark
遗憾皆是温柔11 小时前
MyBatis—动态 SQL
java·数据库·ide·sql·mybatis
未来之窗软件服务11 小时前
Cacti 未经身份验证SQL注入漏洞
android·数据库·sql·服务器安全
拓端研究室TRL11 小时前
Python与MySQL网站排名数据分析及多层感知机MLP、机器学习优化策略和地理可视化应用|附AI智能体数据代码
人工智能·python·mysql·机器学习·数据分析
_星辰大海乀13 小时前
表的设计、聚合函数
java·数据结构·数据库·sql·mysql·数据库开发
Leo.yuan14 小时前
基于地图的数据可视化:解锁地理数据的真正价值
大数据·数据库·信息可视化·数据挖掘·数据分析