ClickHouse提供了許多數據類型,它們可以划分為基礎類型、復合類型和特殊類型。我們可以在system.data_type_families表中檢查數據類型名稱以及是否區分大小寫。
SELECT * FROM system.data_type_families
上面的系統表,存儲了ClickHouse所支持的數據類型,注意不同版本的ClickHouse可能數據類型會有所不同,具體如下表所示:
┌─name────────────────────┬─case_insensitive─┬─alias_to────┐
│ IPv6 │ 0 │ │
│ IPv4 │ 0 │ │
│ LowCardinality │ 0 │ │
│ Decimal │ 1 │ │
│ String │ 0 │ │
│ Decimal64 │ 1 │ │
│ Decimal32 │ 1 │ │
│ Decimal128 │ 1 │ │
│ Float64 │ 0 │ │
│ Float32 │ 0 │ │
│ Int64 │ 0 │ │
│ SimpleAggregateFunction │ 0 │ │
│ Array │ 0 │ │
│ Nothing │ 0 │ │
│ UInt16 │ 0 │ │
│ Enum16 │ 0 │ │
│ UInt32 │ 0 │ │
│ Date │ 1 │ │
│ Int8 │ 0 │ │
│ Int32 │ 0 │ │
│ Enum8 │ 0 │ │
│ UInt64 │ 0 │ │
│ IntervalSecond │ 0 │ │
│ Int16 │ 0 │ │
│ FixedString │ 0 │ │
│ Nullable │ 0 │ │
│ AggregateFunction │ 0 │ │
│ DateTime │ 1 │ │
│ Enum │ 0 │ │
│ Tuple │ 0 │ │
│ IntervalMonth │ 0 │ │
│ Nested │ 0 │ │
│ IntervalMinute │ 0 │ │
│ IntervalHour │ 0 │ │
│ IntervalWeek │ 0 │ │
│ IntervalDay │ 0 │ │
│ UInt8 │ 0 │ │
│ IntervalQuarter │ 0 │ │
│ UUID │ 0 │ │
│ IntervalYear │ 0 │ │
│ LONGBLOB │ 1 │ String │
│ MEDIUMBLOB │ 1 │ String │
│ TINYBLOB │ 1 │ String │
│ BIGINT │ 1 │ Int64 │
│ SMALLINT │ 1 │ Int16 │
│ TIMESTAMP │ 1 │ DateTime │
│ INTEGER │ 1 │ Int32 │
│ INT │ 1 │ Int32 │
│ DOUBLE │ 1 │ Float64 │
│ MEDIUMTEXT │ 1 │ String │
│ TINYINT │ 1 │ Int8 │
│ DEC │ 1 │ Decimal │
│ BINARY │ 1 │ FixedString │
│ FLOAT │ 1 │ Float32 │
│ CHAR │ 1 │ String │
│ VARCHAR │ 1 │ String │
│ TEXT │ 1 │ String │
│ TINYTEXT │ 1 │ String │
│ LONGTEXT │ 1 │ String │
│ BLOB │ 1 │ String │
└─────────────────────────┴──────────────────┴─────────────┘
數值類型
Int類型
固定長度的整數類型又包括有符號和無符號的整數類型。
- 有符號整數類型
| 類型 | 字節 | 范圍 |
|---|---|---|
| Int8 | 1 | [-2^7 ~2^7-1] |
| Int16 | 2 | [-2^15 ~ 2^15-1] |
| Int32 | 4 | [-2^31 ~ 2^31-1] |
| Int64 | 8 | [-2^63 ~ 2^63-1] |
| Int128 | 16 | [-2^127 ~ 2^127-1] |
| Int256 | 32 | [-2^255 ~ 2^255-1] |
- 無符號類型
| 類型 | 字節 | 范圍 |
|---|---|---|
| UInt8 | 1 | [0 ~2^8-1] |
| UInt16 | 2 | [0 ~ 2^16-1] |
| UInt32 | 4 | [0 ~ 2^32-1] |
| UInt64 | 8 | [0 ~ 2^64-1] |
| UInt256 | 32 | [0 ~ 2^256-1] |
浮點類型
- 單精度浮點數
Float32從小數點后第8位起會發生數據溢出
| 類型 | 字節 | 精度 |
|---|---|---|
| Float32 | 4 | 7 |
- 雙精度浮點數
Float32從小數點后第17位起會發生數據溢出
| 類型 | 字節 | 精度 |
|---|---|---|
| Float64 | 8 | 16 |
- 示例
-- Float32類型,從第8為開始產生數據溢出
kms-1.apache.com :) select toFloat32(0.123456789);
SELECT toFloat32(0.123456789)
┌─toFloat32(0.123456789)─┐
│ 0.12345679 │
└────────────────────────┘
-- Float64類型,從第17為開始產生數據溢出
kms-1.apache.com :) select toFloat64(0.12345678901234567890);
SELECT toFloat64(0.12345678901234568)
┌─toFloat64(0.12345678901234568)─┐
│ 0.12345678901234568 │
└────────────────────────────────┘
Decimal類型
有符號的定點數,可在加、減和乘法運算過程中保持精度。ClickHouse提供了Decimal32、Decimal64和Decimal128三種精度的定點數,支持幾種寫法:
-
Decimal(P, S)
-
Decimal32(S)
數據范圍:( -1 * 10^(9 - S), 1 * 10^(9 - S) )
-
Decimal64(S)
數據范圍:( -1 * 10^(18 - S), 1 * 10^(18 - S) )
-
Decimal128(S)
數據范圍: ( -1 * 10^(38 - S), 1 * 10^(38 - S) )
-
Decimal256(S)
數據范圍:( -1 * 10^(76 - S), 1 * 10^(76 - S) )
其中:P代表精度,決定總位數(整數部分+小數部分),取值范圍是1~76
S代表規模,決定小數位數,取值范圍是0~P
根據P的范圍,可以有如下的等同寫法:
| P 取值 | 原生寫法示例 | 等同於 |
|---|---|---|
| [ 1 : 9 ] | Decimal(9,2) | Decimal32(2) |
| [ 10 : 18 ] | Decimal(18,2) | Decimal64(2) |
| [ 19 : 38 ] | Decimal(38,2) | Decimal128(2) |
| [ 39 : 76 ] | Decimal(76,2) | Decimal256(2) |
注意點:不同精度的數據進行四則運算時,**精度(總位數)和規模(小數點位數)**會發生變化,具體規則如下:
-
精度對應的規則
- Decimal64(S1)
運算符Decimal32(S2) -> Decimal64(S) - Decimal128(S1)
運算符Decimal32(S2) -> Decimal128(S) - Decimal128(S1)
運算符Decimal64(S2) -> Decimal128(S) - Decimal256(S1)
運算符Decimal<32|64|128>(S2) -> Decimal256(S)
可以看出:兩個不同精度的數據進行四則運算時,結果數據已最大精度為准
- Decimal64(S1)
-
規模(小數點位數)對應的規則
- 加法|減法:S = max(S1, S2),即以兩個數據中小數點位數最多的為准
- 乘法: S = S1 + S2(注意:S1精度 >= S2精度),即以兩個數據的小數位相加為准
-
除法: S = S1,即被除數的小數位為准
-- toDecimal32(value, S)
-- 加法,S取兩者最大的,P取兩者最大的
SELECT
toDecimal64(2, 3) AS x,
toTypeName(x) AS xtype,
toDecimal32(2, 2) AS y,
toTypeName(y) as ytype,
x + y AS z,
toTypeName(z) AS ztype;
-- 結果輸出
┌─────x─┬─xtype──────────┬────y─┬─ytype─────────┬─────z─┬─ztype──────────┐
│ 2.000 │ Decimal(18, 3) │ 2.00 │ Decimal(9, 2) │ 4.000 │ Decimal(18, 3) │
└───────┴────────────────┴──────┴───────────────┴───────┴────────────────┘
-- 乘法,比較特殊,與這兩個數的順序有關
-- 如下:x類型是Decimal64,y類型是Decimal32,順序是x*y,小數位S=S1+S2
SELECT
toDecimal64(2, 3) AS x,
toTypeName(x) AS xtype,
toDecimal32(2, 2) AS y,
toTypeName(y) as ytype,
x * y AS z,
toTypeName(z) AS ztype;
-- 結果輸出
┌─────x─┬─xtype──────────┬────y─┬─ytype─────────┬───────z─┬─ztype──────────┐
│ 2.000 │ Decimal(18, 3) │ 2.00 │ Decimal(9, 2) │ 4.00000 │ Decimal(18, 5) │
└───────┴────────────────┴──────┴───────────────┴─────────┴────────────────┘
-- 交換相乘的順序,y*x,小數位S=S1*S2
SELECT
toDecimal64(2, 3) AS x,
toTypeName(x) AS xtype,
toDecimal32(2, 2) AS y,
toTypeName(y) as ytype,
y * x AS z,
toTypeName(z) AS ztype;
-- 結果輸出
┌─────x─┬─xtype──────────┬────y─┬─ytype─────────┬────────z─┬─ztype──────────┐
│ 2.000 │ Decimal(18, 3) │ 2.00 │ Decimal(9, 2) │ 0.400000 │ Decimal(18, 6) │
└───────┴────────────────┴──────┴───────────────┴──────────┴────────────────┘
-- 除法,小數位與被除數保持一致
SELECT
toDecimal64(2, 3) AS x,
toTypeName(x) AS xtype,
toDecimal32(2, 2) AS y,
toTypeName(y) as ytype,
x / y AS z,
toTypeName(z) AS ztype;
-- 結果輸出
┌─────x─┬─xtype──────────┬────y─┬─ytype─────────┬─────z─┬─ztype──────────┐
│ 2.000 │ Decimal(18, 3) │ 2.00 │ Decimal(9, 2) │ 1.000 │ Decimal(18, 3) │
└───────┴────────────────┴──────┴───────────────┴───────┴────────────────┘
字符串類型
String
字符串可以是任意長度的。它可以包含任意的字節集,包含空字節。因此,字符串類型可以代替其他 DBMSs 中的VARCHAR、BLOB、CLOB 等類型。
FixedString
固定長度的N字節字符串,一般在在一些明確字符串長度的場景下使用,聲明方式如下:
-- N表示字符串的長度
<column_name> FixedString(N)
值得注意的是:FixedString使用null字節填充末尾字符。
-- 雖然hello只有5位,但最終字符串是6位
select toFixedString('hello',6) as a,length(a) as alength;
-- 結果輸出
┌─a─────┬─alength─┐
│ hello │ 6 │
└───────┴─────────┘
-- 注意對於固定長度的字符串進行比較時,會出現不一樣的結果
-- 如下:由於a是6位字符,而hello是5位,所以兩者不相等
select toFixedString('hello',6) as a,a = 'hello' ,length(a) as alength;
-- 結果輸出
┌─a─────┬─equals(toFixedString('hello', 6), 'hello')─┬─alength─┐
│ hello │ 0 │ 6 │
└───────┴────────────────────────────────────────────┴─────────┘
-- 需要使用下面的方式
select toFixedString('hello',6) as a,a = 'hello\0' ,length(a) as alength;
-- 結果輸出
┌─a─────┬─equals(toFixedString('hello', 6), 'hello\0')─┬─alength─┐
│ hello │ 1 │ 6 │
└───────┴──────────────────────────────────────────────┴─────────┘
UUID
UUID是一種數據庫常見的主鍵類型,在ClickHouse中直接把它作為一種數據類型。UUID共有32位,它的格式為8-4-4-4-12,比如:
61f0c404-5cb3-11e7-907b-a6006ad3dba0
-- 當不指定uuid列的值時,填充為0
00000000-0000-0000-0000-000000000000
使用示例如下:
-- 建表
CREATE TABLE t_uuid (x UUID, y String) ENGINE=TinyLog;
-- insert數據
INSERT INTO t_uuid SELECT generateUUIDv4(), 'Example 1';
INSERT INTO t_uuid (y) VALUES ('Example 2');
SELECT * FROM t_uuid;
-- 結果輸出,默認被填充為0
┌────────────────────────────────────x─┬─y─────────┐
│ b6b019b5-ee5c-4967-9c4d-8ff95d332230 │ Example 1 │
│ 00000000-0000-0000-0000-000000000000 │ Example 2 │
└──────────────────────────────────────┴───────────┘
日期類型
時間類型分為DateTime、DateTime64和Date三類。需要注意的是ClickHouse目前沒有時間戳類型,也就是說,時間類型最高的精度是秒,所以如果需要處理毫秒、微秒精度的時間,則只能借助UInt類型實現。
Date類型
用兩個字節存儲,表示從 1970-01-01 (無符號) 到當前的日期值。日期中沒有存儲時區信息。
CREATE TABLE t_date (x date) ENGINE=TinyLog;
INSERT INTO t_date VALUES('2020-10-01');
SELECT x,toTypeName(x) FROM t_date;
┌──────────x─┬─toTypeName(x)─┐
│ 2020-10-01 │ Date │
└────────────┴───────────────┘
DateTime類型
用四個字節(無符號的)存儲 Unix 時間戳。允許存儲與日期類型相同的范圍內的值。最小值為 0000-00-00 00:00:00。時間戳類型值精確到秒(沒有閏秒)。時區使用啟動客戶端或服務器時的系統時區。
CREATE TABLE t_datetime(`timestamp` DateTime) ENGINE = TinyLog;
INSERT INTO t_datetime Values('2020-10-01 00:00:00');
SELECT * FROM t_datetime;
-- 結果輸出
┌───────────timestamp─┐
│ 2020-10-01 00:00:00 │
└─────────────────────┘
-- 注意,DateTime類型是區分時區的
SELECT
toDateTime(timestamp, 'Asia/Shanghai') AS column,
toTypeName(column) AS x
FROM t_datetime;
-- 結果輸出
┌──────────────column─┬─x─────────────────────────┐
│ 2020-10-01 00:00:00 │ DateTime('Asia/Shanghai') │
└─────────────────────┴───────────────────────────┘
SELECT
toDateTime(timestamp, 'Europe/Moscow') AS column,
toTypeName(column) AS x
FROM t_datetime;
-- 結果輸出
┌──────────────column─┬─x─────────────────────────┐
│ 2020-09-30 19:00:00 │ DateTime('Europe/Moscow') │
└─────────────────────┴───────────────────────────┘
布爾類型
ClickHouse沒有單獨的類型來存儲布爾值。可以使用UInt8 類型,取值限制為0或 1。
數組類型
Array(T),由 T 類型元素組成的數組。T 可以是任意類型,包含數組類型。但不推薦使用多維數組,ClickHouse對多維數組的支持有限。例如,不能在MergeTree表中存儲多維數組。
SELECT array(1, 2) AS x, toTypeName(x);
-- 結果輸出
┌─x─────┬─toTypeName(array(1, 2))─┐
│ [1,2] │ Array(UInt8) │
└───────┴─────────────────────────┘
SELECT [1, 2] AS x, toTypeName(x);
-- 結果輸出
┌─x─────┬─toTypeName([1, 2])─┐
│ [1,2] │ Array(UInt8) │
└───────┴────────────────────┘
需要注意的是,數組元素中如果存在Null值,則元素類型將變為Nullable。
SELECT array(1, 2, NULL) AS x, toTypeName(x);
-- 結果輸出
┌─x──────────┬─toTypeName(array(1, 2, NULL))─┐
│ [1,2,NULL] │ Array(Nullable(UInt8)) │
└────────────┴───────────────────────────────┘
另外,數組類型里面的元素必須具有相同的數據類型,否則會報異常
SELECT array(1, 'a')
-- 報異常
DB::Exception: There is no supertype for types UInt8, String because some of them are String/FixedString and some of them are not
枚舉類型
枚舉類型通常在定義常量時使用,ClickHouse提供了Enum8和Enum16兩種枚舉類型。
-- 建表
CREATE TABLE t_enum
(
x Enum8('hello' = 1, 'world' = 2)
)
ENGINE = TinyLog;
-- INSERT數據
INSERT INTO t_enum VALUES ('hello'), ('world'), ('hello');
-- 如果定義了枚舉類型值之后,不能寫入其他值的數據
INSERT INTO t_enum values('a')
-- 報異常:Unknown element 'a' for type Enum8('hello' = 1, 'world' = 2)
Tuple類型
Tuple(T1, T2, …),元組,與Array不同的是,Tuple中每個元素都有單獨的類型,不能在表中存儲元組(除了內存表)。它們可以用於臨時列分組。在查詢中,IN表達式和帶特定參數的 lambda 函數可以來對臨時列進行分組。
SELECT tuple(1,'a') AS x, toTypeName(x);
--結果輸出
┌─x───────┬─toTypeName(tuple(1, 'a'))─┐
│ (1,'a') │ Tuple(UInt8, String) │
└─────────┴───────────────────────────┘
-- 建表
CREATE TABLE t_tuple(
c1 Tuple(String,Int8)
) engine=TinyLog;
-- INSERT數據
INSERT INTO t_tuple VALUES(('jack',20));
--查詢數據
SELECT * FROM t_tuple;
┌─c1──────────┐
│ ('jack',20) │
└─────────────┘
-- 如果插入數據類型不匹配,會報異常
INSERT INTO t_tuple VALUES(('tom','20'));
-- Type mismatch in IN or VALUES section. Expected: Int8. Got: String
特殊數據類型
Nullable
Nullable類型表示某個基礎數據類型可以是Null值。其具體用法如下所示:
-- 建表
CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE TinyLog
-- 寫入數據
INSERT INTO t_null VALUES (1, NULL), (2, 3);
SELECT x + y FROM t_null;
-- 結果
┌─plus(x, y)─┐
│ ᴺᵁᴸᴸ │
│ 5 │
└────────────┘
Domain
Domain類型是特定實現的類型:
IPv4是與UInt32類型保持二進制兼容的Domain類型,用於存儲IPv4地址的值。它提供了更為緊湊的二進制存儲的同時支持識別可讀性更加友好的輸入輸出格式。
IPv6是與FixedString(16)類型保持二進制兼容的Domain類型,用於存儲IPv6地址的值。它提供了更為緊湊的二進制存儲的同時支持識別可讀性更加友好的輸入輸出格式。
注意低版本的ClickHouse不支持此類型。
-- 建表
CREATE TABLE hits
(url String,
from IPv4
) ENGINE = MergeTree()
ORDER BY from;
-- 寫入數據
INSERT INTO hits (url, from) VALUES
('https://wikipedia.org', '116.253.40.133')
('https://clickhouse.tech', '183.247.232.58');
-- 查詢
SELECT * FROM hits;
┌─url─────────────────────┬───────────from─┐
│ https://wikipedia.org │ 116.253.40.133 │
│ https://clickhouse.tech │ 183.247.232.58 │
└─────────────────────────┴────────────────┘
公眾號『大數據技術與數倉』,回復『資料』領取大數據資料包
