1. 程式人生 > 其它 >五 ClickHouse查詢語法

五 ClickHouse查詢語法

5.1 with

ClickHouse支援CTE(Common Table Expression,公共表表達式),以增強查詢語句的表達

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

在改用CTE的形式後,可以極大地提高語句的可讀性和可維護性,\

with pow(2,2) as a select pow(a,3) ;

1) 定義變數

WITH 
    1 AS start,
    10 AS end
SELECT 
    id + start,
    *
FROM tb_mysql
​
┌─plus(id, start)─┬─id─┬─name─┬─age─┐
│               2 │  1 │ zss  │  23 │
│               3 │  2 │ lss  │  33 │
│               4 │  3 │ ww   │  44 │
│               2 │  1 │ zss  │  23 │
│               3 │  2 │ lss  │  33 │
│               2 │  1 │ zss  │  23 │
│               3 │  2 │ lss  │  33 │
└─────────────────┴────┴──────┴─────┘

2) 呼叫函式

SELECT *
FROM tb_partition
┌─id─┬─name─┬────────────birthday─┐
│  1 │ xl   │ 2021-05-20 10:50:46 │
│  2 │ xy   │ 2021-05-20 11:17:47 │
└────┴──────┴─────────────────────┘
┌─id─┬─name─┬────────────birthday─┐
│  3 │ xf   │ 2021-05-19 11:11:12 │
└────┴──────┴───────────---------─┘
WITH toDate(birthday) AS bday
SELECT 
    id,
    name,
    bday
FROM tb_partition
​
┌─id─┬─name─┬───────bday─┐
│  1 │ xl   │ 2021-05-20 │
│  2 │ xy   │ 2021-05-20 │
└────┴──────┴────────────┘
┌─id─┬─name─┬───────bday─┐
│  3 │ xf   │ 2021-05-19 │
└────┴──────┴────────────┘

3) 子查詢

可以定義子查詢 ,但是一定還要注意的是,子查詢只能返回一行結果 ,否則會跑出異常

WITH 
    (
        SELECT *
        FROM tb_partition
        WHERE id = 1
    ) AS sub
SELECT 
    *,
    sub
FROM tb_partition
​
┌─id─┬─name─┬────────────birthday─┬─sub────────────────────────────┐
│  1 │ xl   │ 2021-05-20 10:50:46 │ (1,'xl','2021-05-20 10:50:46') │
│  2 │ xy   │ 2021-05-20 11:17:47 │ (1,'xl','2021-05-20 10:50:46') │
└────┴──────┴─────────────────────┴────────────────────────────────┘
┌─id─┬─name─┬────────────birthday─┬─sub────────────────────────────┐
│  3 │ xf   │ 2021-05-19 11:11:12 │ (1,'xl','2021-05-20 10:50:46') │
└────┴──────┴─────────────────────┴────────────────────────────────┘

5.2 from

SQL是一種面向集合的程式語言 ,from決定了程式從那裡讀取資料

  1. 表中查詢資料

  2. 子查詢中查詢資料

  3. 表函式中查詢資料 select * from numbers(3) ;

表函式

構建表的函式 , 使用場景如下:

SELECT查詢的[FROM)子句。

建立表AS 查詢。

1 file

file(path, format, structure)
path — The relative path to the file from user_files_path. Path to file support following globs in readonly mode: *, ?, {abc,def} and {N..M} where N, M — numbers, `'abc', 'def' — strings.
format — The format of the file.
structure — Structure of the table. Format 'column1_name column1_type, column2_name column2_type, ...'. 

資料檔案必須在指定的目錄下 /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') 

2 numbers

SELECT *
FROM numbers(10) ;
​
SELECT *
FROM numbers(2, 10) ;
​
SELECT *
FROM numbers(10) limit 3 ;
​
SELECT toDate('2020-01-01') + number AS d
FROM numbers(365)
3 mysql
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')

4 hdfs

SELECT *FROM hdfs('hdfs://hdfs1:9000/test', 'TSV', 'column1 UInt32, column2 UInt32, column3 UInt32')LIMIT 2

SELECT *

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

5.3 array join

ARRAY JOIN子句允許在資料表的內部,與陣列或巢狀型別的欄位進行JOIN操作,從而將一行陣列展開為多行。類似於hive中的explode炸裂函式的功能!

CREATE TABLE test_arrayjoin
(
    `name` String,
    `vs` Array(Int8)
)
ENGINE = Memory ;
insert into test_arrayjoin values('xw',[1,2,3]),('xl',[4,5]),('xk',[1]);
-- 將陣列中的資料展開
SELECT 
    *,
    s
FROM test_arrayjoin
ARRAY JOIN vs AS s
┌─name─┬─vs──────┬─s─┐
│ xw   │ [1,2,3] │ 1 │
│ xw   │ [1,2,3] │ 2 │
│ xw   │ [1,2,3] │ 3 │
│ xl   │ [4,5]   │ 4 │
│ xl   │ [4,5]   │ 5 │
│ xk   │ [1]     │ 1 │
└──────┴─────────┴───┘
-- arrayMap 高階函式,對陣列中的每個元素進行操作
SELECT 
    *,
    arrayMap(x->x*2 , vs) vs2
FROM test_arrayjoin ;
SELECT 
    *,
    arrayMap(x -> (x * 2), vs) AS vs2
FROM test_arrayjoin
┌─name─┬─vs──────┬─vs2─────┐
│ xw   │ [1,2,3] │ [2,4,6] │
│ xl   │ [4,5]   │ [8,10]  │
│ xk   │ [1]     │ [2]     │
└──────┴─────────┴─────────┘
SELECT 
    *,
    arrayMap(x -> (x * 2), vs) AS vs2 ,
    vv1 ,
    vv2
FROM test_arrayjoin
array join 
vs as vv1 ,
vs2 as vv2 ;
┌─name─┬─vs──────┬─vs2─────┬─vv1─┬─vv2─┐
│ xw   │ [1,2,3] │ [2,4,6] │   1 │   2 │
│ xw   │ [1,2,3] │ [2,4,6] │   2 │   4 │
│ xw   │ [1,2,3] │ [2,4,6] │   3 │   6 │
│ xl   │ [4,5]   │ [8,10]  │   4 │   8 │
│ xl   │ [4,5]   │ [8,10]  │   5 │  10 │
│ xk   │ [1]     │ [2]     │   1 │   2 │
└──────┴─────────┴─────────┴─────┴─────┘
select
id ,
h ,
xx
from
tb_array_join 
array join 
hobby  as h  ,
arrayEnumerate(hobby) as xx ;
┌─id─┬─h─────┬─xx─┐
│  1 │ eat   │  1 │
│  1 │ drink │  2 │
│  1 │ sleep │  3 │
│  2 │ study │  1 │
│  2 │ sport │  2 │
│  2 │ read  │  3 │
└────┴───────┴────┘
┌─id─┬─h─────┬─xx─┐
│  3 │ eat   │  1 │
│  3 │ drink │  2 │

  

案例

a,2017-02-05,200
a,2017-02-06,300
a,2017-02-07,200
a,2017-02-08,400
a,2017-02-08,300
a,2017-02-10,600
b,2017-02-05,200
b,2017-02-06,300
b,2017-02-08,200
b,2017-02-09,400
b,2017-02-10,600
c,2017-01-31,200
c,2017-02-01,300
c,2017-02-02,200
c,2017-02-03,400
c,2017-02-10,600
a,2017-03-01,200
a,2017-03-02,300
a,2017-03-03,200
a,2017-03-04,400
a,2017-03-05,600
drop table if exists tb_shop ;
CREATE TABLE tb_shop
(
    `name` String,
    `cdate` Date,
    `cost` Float64
)engine=ReplacingMergeTree(cdate)
order by (name,cdate) ;
-- 匯入資料
clickhouse-client -q 'insert into doit23.tb_shop format CSV' < shop.txt ;  
┌─name─┬──────cdate─┬─cost─┐
│ a    │ 2017-02-05 │  200 │
│ a    │ 2017-02-06 │  300 │
│ a    │ 2017-02-07 │  200 │
│ a    │ 2017-02-08 │  400 │
│ a    │ 2017-02-10 │  600 │
│ a    │ 2017-03-01 │  200 │
│ a    │ 2017-03-02 │  300 │
│ a    │ 2017-03-03 │  200 │
│ a    │ 2017-03-04 │  400 │
│ a    │ 2017-03-05 │  888 │
│ b    │ 2017-02-05 │  200 │
│ b    │ 2017-02-06 │  300 │
│ b    │ 2017-02-08 │  200 │
│ b    │ 2017-02-09 │  400 │
│ b    │ 2017-02-10 │  600 │
│ c    │ 2017-01-31 │  200 │
│ c    │ 2017-02-01 │  300 │
│ c    │ 2017-02-02 │  200 │
│ c    │ 2017-02-03 │  400 │
│ c    │ 2017-02-10 │  600 │
└──────┴────────────┴──────┘
select
 name ,
 groupArray(cdate) arr ,
 arrayEnumerate(arr) as indexs
from
tb_shop
group by name;
​
┌─name─┬─arr─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─indexs─────────────────┐
│ b    │ ['2017-02-05','2017-02-06','2017-02-08','2017-02-09','2017-02-10']                                                                  │ [1,2,3,4,5]            │
│ c    │ ['2017-01-31','2017-02-01','2017-02-02','2017-02-03','2017-02-10']                                                                  │ [1,2,3,4,5]            │
│ a    │ ['2017-02-05','2017-02-06','2017-02-07','2017-02-08','2017-02-10','2017-03-01','2017-03-02','2017-03-03','2017-03-04','2017-03-05'] │ [1,2,3,4,5,6,7,8,9,10] │
└──────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────────────┘
select 
name ,
dt - num
from
(select
 name ,
 groupArray(cdate) arr ,
 arrayEnumerate(arr) as indexs
from
tb_shop
group by name
)
array  join 
arr as dt ,
indexs as num ;
┌─name─┬─minus(dt, num)─┐
│ b    │     2017-02-04 │
│ b    │     2017-02-04 │
│ b    │     2017-02-05 │
│ b    │     2017-02-05 │
│ b    │     2017-02-05 │
│ c    │     2017-01-30 │
│ c    │     2017-01-30 │
│ c    │     2017-01-30 │
│ c    │     2017-01-30 │
│ c    │     2017-02-05 │
│ a    │     2017-02-04 │
│ a    │     2017-02-04 │
│ a    │     2017-02-04 │
│ a    │     2017-02-04 │
│ a    │     2017-02-05 │
│ a    │     2017-02-23 │
│ a    │     2017-02-23 │
│ a    │     2017-02-23 │
│ a    │     2017-02-23 │
│ a    │     2017-02-23 │
└──────┴────────────────┘
select
name ,
diff ,
count(1) cnt
from
(select 
name ,
(dt - num) as diff
from
(select
 name ,
 groupArray(cdate) arr ,
 arrayEnumerate(arr) as indexs
from
tb_shop
group by name
)
array  join 
arr as dt ,
indexs as num
)
group by name , diff;
​
┌─name─┬───────diff─┬─count(1)─┐
│ b    │ 2017-02-04 │        2 │
│ a    │ 2017-02-23 │        5 │
│ c    │ 2017-01-30 │        4 │
│ c    │ 2017-02-05 │        1 │
│ a    │ 2017-02-04 │        4 │
│ b    │ 2017-02-05 │        3 │
│ a    │ 2017-02-05 │        1 │
└──────┴────────────┴──────────┘
select
name ,
diff ,
count(1) cnt
from
(select 
name ,
(dt - num) as diff
from
(select
 name ,
 groupArray(cdate) arr ,
 arrayEnumerate(arr) as indexs
from
tb_shop
group by name
)
array  join 
arr as dt ,
indexs as num
)
group by name , diff
order by cnt desc 
limit 1 by name  ;
​
┌─name─┬───────diff─┬─cnt─┐
│ a    │ 2017-02-23 │   5 │
│ c    │ 2017-01-30 │   4 │
│ b    │ 2017-02-05 │   3 │
└──────┴────────────┴─────┘

5.4 關聯查詢

所有標準 SQL JOIN 支援型別:

  • INNER JOIN, only matching rows are returned.

  • LEFT OUTER JOIN, non-matching rows from left table are returned in addition to matching rows.

  • RIGHT OUTER JOIN, non-matching rows from right table are returned in addition to matching rows.

  • FULL OUTER JOIN, non-matching rows from both tables are returned in addition to matching rows.

  • CROSS JOIN, produces cartesian product of whole tables, “join keys” are not specified.

JOIN子句可以對左右兩張表的資料進行連線,這是最常用的查詢子句之一。它的語法包含連線精度和連線型別兩部分。

連線精度

連線精度決定了JOIN查詢在連線資料時所使用的策略,目前支援ALL、ANY和ASOF三種類型。如果不主動宣告,則預設是ALL。可以通過join_default_strictness配置引數修改預設的連線精度型別。

對資料是否連線匹配的判斷是通過JOIN KEY進行的,目前只支援等式(EQUAL JOIN)。交叉連線(CROSS JOIN)不需要使用JOIN KEY,因為它會產生笛卡兒積。

-- 準備資料
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,2) ,
(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 ;
drop table 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),(5,5000,2000);

1)all

如果左表內的一行資料,在右表中有多行資料與之連線匹配,則返回右表中全部連線的資料。而判斷連線匹配的依據是左表與右表內的資料,基於連線鍵(JOIN KEY)的取值完全相等(equal),等同於 left.key=right.key。

SELECT *
FROM yg AS inser
ALL INNER JOIN gz ON yg.id = gz.id ;
SELECT *
FROM yg AS inser
ALL  JOIN gz ON yg.id = gz.id ;
SELECT *
FROM yg AS inser
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 │   2 │     2 │ 2000 │ 1233 │
│  3 │ VV   │  27 │   1 │     3 │ 2000 │ 3000 │
│  4 │ CC   │  13 │   3 │     4 │ 4000 │ 1000 │
│  5 │ KK   │  53 │   3 │     5 │ 5000 │ 2000 │
└────┴──────┴─────┴─────┴───────┴──────┴──────┘ 

2)any

如果左表內的一行資料,在右表中有多行資料與之連線匹配,則僅返回右表中第一行連線的資料。ANY與ALL判斷連線匹配的依據相同。

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 │   2 │     2 │ 2000 │ 1233 │
│  3 │ VV   │  27 │   1 │     3 │ 2000 │ 3000 │
│  4 │ CC   │  13 │   3 │     4 │ 4000 │ 1000 │
│  5 │ KK   │  53 │   3 │     5 │ 5000 │ 2000 │
└────┴──────┴─────┴─────┴───────┴──────┴──────┘

3)asof

asof連線鍵之後追加定義一個模糊連線的匹配條件asof_column。

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-01 00:00:00'),
(3,'dd','2021-01-01 00:00:00');
​
-- ASOF inner join 
SELECT *
FROM emp2
ASOF INNER JOIN emp1 ON (emp1.id = emp2.id) AND (emp1.ctime > emp2.ctime)
​
┌─id─┬─name─┬───────────────ctime─┬─emp1.id─┬─emp1.name─┬──────────emp1.ctime─┐
│  1 │ aa   │ 2021-01-02 00:00:00 │       1 │ AA        │ 2021-01-03 00:00:00 │
│  1 │ aa   │ 2021-01-02 00:00:00 │       1 │ AA        │ 2021-01-03 00:00:00 │
└────┴──────┴─────────────────────┴─────────┴───────────┴─────────────────────┘

5.5 with模型

  • With cube

  • With rollup

  • With totals

drop table is 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,12,'山東','濟南','天橋') ;
insert into tb_with values(5,88,'山東','青島','黃島') ;
insert into tb_with values(6,88,'山東','青島','黃島') ;
insert into tb_with values(7,12,'山西','太原','小店') ;
insert into tb_with values(8,12,'山西','太原','小店') ;
insert into tb_with values(9,112,'山西','太原','尖草坪') ;
SELECT 
    province,
    city,
    area,
    sum(vist)
FROM tb_with
GROUP BY 
    province,
    city,
    area
    WITH CUBE ;
  ┌─province─┬─city─┬─area───┬─sum(vist)─┐
│ 山東     │ 青島 │ 黃島   │       176 │
│ 山東     │ 濟南 │ 天橋   │        24 │
│ 山東     │ 太原 │ 尖草坪 │       112 │
│ 山東     │ 濟南 │ 歷下   │        24 │
│ 山西     │ 太原 │ 小店   │        12 │
│ 山東     │ 太原 │ 小店   │        12 │
└──────────┴──────┴────────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│ 山東     │ 青島 │      │       176 │
│ 山東     │ 濟南 │      │        48 │
│ 山西     │ 太原 │      │        12 │
│ 山東     │ 太原 │      │       124 │
└──────────┴──────┴──────┴───────────┘
┌─province─┬─city─┬─area───┬─sum(vist)─┐
│ 山東     │      │ 歷下   │        24 │
│ 山東     │      │ 小店   │        12 │
│ 山東     │      │ 天橋   │        24 │
│ 山西     │      │ 小店   │        12 │
│ 山東     │      │ 尖草坪 │       112 │
│ 山東     │      │ 黃島   │       176 │
└──────────┴──────┴────────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│ 山西     │      │      │        12 │
│ 山東     │      │      │       348 │
└──────────┴──────┴──────┴───────────┘
┌─province─┬─city─┬─area───┬─sum(vist)─┐
│          │ 濟南 │ 歷下   │        24 │
│          │ 濟南 │ 天橋   │        24 │
│          │ 太原 │ 尖草坪 │       112 │
│          │ 青島 │ 黃島   │       176 │
│          │ 太原 │ 小店   │        24 │
└──────────┴──────┴────────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│          │ 青島 │      │       176 │
│          │ 濟南 │      │        48 │
│          │ 太原 │      │       136 │
└──────────┴──────┴──────┴───────────┘
┌─province─┬─city─┬─area───┬─sum(vist)─┐
│          │      │ 天橋   │        24 │
│          │      │ 小店   │        24 │
│          │      │ 黃島   │       176 │
│          │      │ 歷下   │        24 │
│          │      │ 尖草坪 │       112 │
└──────────┴──────┴────────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│          │      │      │       360 │
└──────────┴──────┴──────┴───────────┘
 SELECT 
    province,
    city,
    area,
    sum(vist)
FROM tb_with
GROUP BY 
    province,
    city,
    area
    WITH ROLLUP;
​
┌─province─┬─city─┬─area───┬─sum(vist)─┐
│ 山東     │ 青島 │ 黃島   │       176 │
│ 山東     │ 濟南 │ 天橋   │        24 │
│ 山東     │ 太原 │ 尖草坪 │       112 │
│ 山東     │ 濟南 │ 歷下   │        24 │
│ 山西     │ 太原 │ 小店   │        12 │
│ 山東     │ 太原 │ 小店   │        12 │
└──────────┴──────┴────────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│ 山東     │ 青島 │      │       176 │
│ 山東     │ 濟南 │      │        48 │
│ 山西     │ 太原 │      │        12 │
│ 山東     │ 太原 │      │       124 │
└──────────┴──────┴──────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│ 山西     │      │      │        12 │
│ 山東     │      │      │       348 │
└──────────┴──────┴──────┴───────────┘
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│          │      │      │       360 │
└──────────┴──────┴──────┴───────────┘
SELECT 
    province,
    city,
    area,
    sum(vist)
FROM tb_with
GROUP BY 
    province,
    city,
    area
    WITH TOTALS;
┌─province─┬─city─┬─area───┬─sum(vist)─┐
│ 山東     │ 青島 │ 黃島   │       176 │
│ 山東     │ 濟南 │ 天橋   │        24 │
│ 山東     │ 太原 │ 尖草坪 │       112 │
│ 山東     │ 濟南 │ 歷下   │        24 │
│ 山西     │ 太原 │ 小店   │        12 │
│ 山東     │ 太原 │ 小店   │        12 │
└──────────┴──────┴────────┴───────────┘
Totals:
┌─province─┬─city─┬─area─┬─sum(vist)─┐
│          │      │      │       360 │
└──────────┴──────┴──────┴───────────┘