最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

KingbaseES數(shù)據(jù)類型從基礎CHAR到JSON/XML/幾何類型完全指南

 更新時間:2026年05月07日 09:43:02   作者:鴿芷咕  
在數(shù)據(jù)類型體系方面,KingbaseES展現(xiàn)出極強的完備性與專業(yè)性,這篇文章主要介紹了KingbaseES數(shù)據(jù)類型從基礎CHAR到JSON/XML/幾何類型的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

你有沒有遇到過這種情況——建表的時候隨便選了個VARCHAR,結果存金額的時候精度丟了;或者存IP地址用了字符串,查詢的時候怎么都篩不準?

說白了,這些問題都跟數(shù)據(jù)類型的選擇有關。選對類型,數(shù)據(jù)存得準、查得快;選錯了,小則浪費空間,大則數(shù)據(jù)失真。

這篇文章我把數(shù)據(jù)庫里所有內置數(shù)據(jù)類型都梳理了一遍,從最常用的字符、數(shù)值,到JSON、XML、幾何類型,每個都配上了實際能跑的代碼。不管你是剛入門還是已經寫過不少SQL,都能用得上。

一、字符類型:存文本,這幾個就夠了

字符類型是打交道最多的,存名字、存地址、存?zhèn)渥⒍茧x不開它。說簡單點,就是數(shù)據(jù)庫里專門用來"裝文字"的容器。

數(shù)據(jù)庫同時支持單字節(jié)和多字節(jié)字符集,中英文混合存儲完全沒問題。

1.1 CHAR——固定長度,不夠就補空格

CHAR是定長字符串。什么意思呢?你定義一個CHAR(10),不管往里塞"abc"還是"一二三四五",數(shù)據(jù)庫都會把內容補齊到10個字符長度——不夠的用空格填。

語法很簡單:

CHAR [(size [BYTE | CHAR])]

size最大能到2000。這里有個容易踩坑的地方:長度單位到底是"字節(jié)"還是"字符"?

-- 按字符算:一個中文算1個字符,一個英文也算1個字符
CREATE TABLE test_char (col CHAR(4 CHAR));
INSERT INTO test_char VALUES ('一二三四');   -- 沒問題,剛好4個字符
INSERT INTO test_char VALUES ('一二三四五'); -- 報錯!超了1個字符

-- 按字節(jié)算:一個中文通常占3個字節(jié),一個英文占1個字節(jié)
CREATE TABLE test_byte (col CHAR(4 BYTE));
INSERT INTO test_byte VALUES ('1234');  -- 沒問題,4個ASCII字符=4字節(jié)
INSERT INTO test_byte VALUES ('一二三'); -- 報錯!3個中文=9字節(jié),遠超4字節(jié)限制

什么時候該用CHAR?當你的數(shù)據(jù)長度基本一致的時候——手機號、身份證號、固定編碼,這類場景用CHAR最合適,查詢效率也更高。

1.2 VARCHAR2——用多少占多少,最靈活

VARCHAR2是日常開發(fā)中用得最多的變長字符串類型。跟CHAR不同,它不會用空格去填充,實際內容占多少就存多少。

VARCHAR2(size [BYTE | CHAR])

最大能存多長?這取決于一個系統(tǒng)參數(shù)MAX_STRING_SIZE

參數(shù)值最大長度
STANDARD4000字節(jié)
EXTENDED32767字節(jié)

來看個實際的例子:

CREATE TABLE user_info (
    user_id   INT,
    username  VARCHAR2(50 CHAR),    -- 最多50個字符
    email     VARCHAR2(100 BYTE),   -- 最多100個字節(jié)
    bio       VARCHAR2(500 CHAR)    -- 個人簡介,最多500個字符
);

INSERT INTO user_info VALUES (1, '張三', 'zhangsan@example.com', '全棧開發(fā)工程師');

-- VARCHAR2會原樣存儲,不會補空格
SELECT username, length(username) FROM user_info;
-- 結果:張三 | 2(實際字符長度)

順便提一句,VARCHAR和VARCHAR2功能完全一樣,可以互換使用。另外CHARACTER VARYING、CHAR VARYING也都是它的別名。

1.3 NCHAR與NVARCHAR2——多語言場景的標配

如果你的應用要同時支持中英日韓多國語言,那就得請出NCHAR和NVARCHAR2了。它們用Unicode國際字符集存儲,不管什么語言的字符都能正確保存,不會出現(xiàn)亂碼。

-- NCHAR:定長的Unicode字符串
-- NVARCHAR2:變長的Unicode字符串
CREATE TABLE multilang (
    label    NCHAR(20),            -- 固定20個Unicode字符位
    content  NVARCHAR2(500 CHAR)   -- 變長,最多500個Unicode字符
);

-- 中英日文混合存儲,完全沒問題
INSERT INTO multilang VALUES ('Hello世界こんにちは', '多語言內容存儲示例');

SELECT label, content FROM multilang;

兩者的容量限制:

類型編碼方式最大字符數(shù)
NCHARAL16UTF161000字符
NCHARUTF82000字符
NVARCHAR2EXTENDED模式最大32767字節(jié)
NVARCHAR2STANDARD模式最大4000字節(jié)

簡單總結一下字符類型的選擇思路:長度固定用CHAR,長度變化用VARCHAR2,涉及多語言就用NCHAR/NVARCHAR2。

二、數(shù)值類型:錢用NUMBER,計數(shù)用INT

數(shù)值類型看起來簡單,但選錯了后果很嚴重——尤其是涉及錢的時候。

數(shù)據(jù)庫能存整數(shù)、小數(shù)、正數(shù)、負數(shù)、零,甚至還有幾個特殊值:Infinity(正無窮)、-Infinity(負無窮)和NaN(不是數(shù)字)。

2.1 NUMBER——萬能數(shù)值,精度你說了算

NUMBER是最通用的數(shù)值類型,你可以精確控制它保留多少位有效數(shù)字、多少位小數(shù)。

NUMBER [(precision [, scale])]
  • precision(精度):有效數(shù)字總共多少位,范圍1~1000
  • scale(標度):小數(shù)點后保留幾位,范圍-84~1000。標度還能是負數(shù),表示從個位開始往左舍入

直接看例子最直觀:

CREATE TABLE financial_records (
    record_id   NUMBER(10),        -- 10位整數(shù),足夠存ID
    unit_price  NUMBER(8,2),       -- 8位有效數(shù)字、2位小數(shù),如 999999.99
    total       NUMBER(12,2),      -- 12位有效數(shù)字、2位小數(shù),適合存大額金額
    round_value NUMBER(12,-2)      -- 標度為負,自動舍入到百位
);

-- 實際插入數(shù)據(jù)
INSERT INTO financial_records VALUES (100001, 29.90, 2990.00, 123456);
-- round_value 列存入123456,實際會被存為 123500(百位以下舍入)

SELECT * FROM financial_records;

精度和標度的效果演示:

-- 四舍五入到3位有效數(shù)字
SELECT CAST(123.89 AS NUMBER(3));      -- 輸出:124

-- 保留2位小數(shù)
SELECT CAST(123.89 AS NUMBER(5,2));    -- 輸出:123.89

-- 保留1位小數(shù),第2位小數(shù)四舍五入
SELECT CAST(123.89 AS NUMBER(6,1));    -- 輸出:123.9

-- 小數(shù)點后5位,適合存精度很高的數(shù)據(jù)
SELECT CAST(0.000127 AS NUMBER(4,5));  -- 輸出:0.00013

-- 超出精度直接報錯
SELECT CAST(123.89 AS NUMBER(3,2));
-- ERROR: 超出精度范圍

2.2 INT與SMALLINT——存整數(shù),輕量又高效

如果你要存的只是整數(shù)(比如ID、數(shù)量、年齡),那用INT或SMALLINT比NUMBER更高效:

類型取值范圍占用空間
INT(別名INTEGER)-2,147,483,648 ~ 2,147,483,6474字節(jié)
SMALLINT-32,768 ~ 32,7672字節(jié)
CREATE TABLE orders (
    order_id   INT,            -- 訂單編號,21億以內夠用了
    quantity   SMALLINT,       -- 購買數(shù)量,3萬多個也夠了
    status     SMALLINT        -- 狀態(tài)碼:0待付款 1已付款 2已發(fā)貨 3已完成
);

INSERT INTO orders VALUES (100001, 5, 0);
INSERT INTO orders VALUES (100002, 120, 1);

SELECT * FROM orders WHERE quantity > 10;

經驗法則:一般業(yè)務數(shù)據(jù)用INT就夠了,如果是狀態(tài)碼、排序號這種小范圍的值,SMALLINT更省空間。

2.3 浮點類型——科學計算用,別拿來存錢

FLOAT是可變精度的浮點數(shù)。當你需要存科學數(shù)據(jù)、傳感器讀數(shù)這類對"絕對精確"要求不高的數(shù)值時,浮點類型就派上用場了。

-- FLOAT:precision為1~24時是單精度(REAL),25~53時是雙精度(DOUBLE PRECISION)
-- BINARY_FLOAT:32位單精度,范圍 1.17549E-38 ~ 3.40282E+38
-- BINARY_DOUBLE:64位雙精度,范圍 2.22507E-308 ~ 1.79769E+308

實際使用:

CREATE TABLE sensor_data (
    sensor_id    INT,
    temperature  BINARY_FLOAT,    -- 溫度傳感器讀數(shù)
    pressure     BINARY_DOUBLE,   -- 氣壓傳感器讀數(shù)
    recorded_at  TIMESTAMP
);

-- 浮點數(shù)的字面量寫法
INSERT INTO sensor_data VALUES (1, 36.5F, 101325.0D, CURRENT_TIMESTAMP);
INSERT INTO sensor_data VALUES (2, -0.1F, 101200.5D, CURRENT_TIMESTAMP);

-- 查詢浮點數(shù)據(jù)
SELECT sensor_id, temperature, pressure FROM sensor_data;

-- 浮點數(shù)支持特殊值
SELECT 'Infinity'::float8;   -- 正無窮
SELECT '-Infinity'::float8;  -- 負無窮
SELECT 'NaN'::float8;        -- 不是數(shù)字

重點提醒:浮點數(shù)用的是二進制存儲,沒法精確表示某些十進制小數(shù)(比如0.1)。所以,凡是跟錢沾邊的,一律用NUMBER,千萬別用FLOAT!

三、日期時間類型:不只是"存?zhèn)€日期"那么簡單

時間看起來簡單,但真要在業(yè)務里用好,得區(qū)分好幾種不同的精度和場景。

3.1 DATE——基本的日期+時間

DATE存的是年、月、日、時、分、秒,從公元前4713年到公元5874897年,跨度大得離譜。

CREATE TABLE events (
    event_id   INT,
    event_name VARCHAR2(100),
    event_date DATE
);

-- 用TO_DATE把字符串轉成DATE
INSERT INTO events VALUES (1, '項目啟動', TO_DATE('2024-12-01', 'YYYY-MM-DD'));
INSERT INTO events VALUES (2, '年終總結', TO_DATE('2024-12-31 14:00:00', 'YYYY-MM-DD HH24:MI:SS'));

-- 不指定時間的話,默認是午夜 00:00:00
SELECT event_name, event_date FROM events;
-- 輸出:
-- 項目啟動 | 2024-12-01 00:00:00
-- 年終總結 | 2024-12-31 14:00:00

-- DATE之間可以直接做加減
SELECT event_name, event_date - TO_DATE('2024-12-01','YYYY-MM-DD') AS days_diff
FROM events;
-- 輸出:
-- 項目啟動 | 0
-- 年終總結 | 30

3.2 TIMESTAMP——精確到毫秒甚至微秒

TIMESTAMP是DATE的"加強版",在年月日時分秒之外,還能存小數(shù)秒,精度最高到6位(微秒級)。

TIMESTAMP [(fractional_seconds_precision)]  -- 小數(shù)秒位數(shù),0~6,默認6
CREATE TABLE system_log (
    log_id    INT,
    log_time  TIMESTAMP(3),     -- 精確到毫秒(3位小數(shù))
    level     VARCHAR2(10),
    message   VARCHAR2(500)
);

-- 插入帶毫秒精度的時間
INSERT INTO system_log VALUES (
    1,
    TO_TIMESTAMP('2024-01-01 09:30:53.123', 'YYYY-MM-DD HH24:MI:SS.FF3'),
    'INFO',
    '系統(tǒng)啟動完成'
);

INSERT INTO system_log VALUES (
    2,
    TO_TIMESTAMP('2024-01-01 09:30:53.456', 'YYYY-MM-DD HH24:MI:SS.FF3'),
    'ERROR',
    '數(shù)據(jù)庫連接超時'
);

-- 精確到毫秒的查詢
SELECT log_id, log_time, level, message FROM system_log
WHERE log_time > TO_TIMESTAMP('2024-01-01 09:30:53.200', 'YYYY-MM-DD HH24:MI:SS.FF3');

3.3 帶時區(qū)的時間戳——跨時區(qū)應用的必備

如果你的用戶分布在北京、紐約、倫敦,時間戳就得帶上時區(qū)信息,不然時間就全亂套了。

數(shù)據(jù)庫提供了兩種帶時區(qū)的TIMESTAMP:

  • TIMESTAMP WITH TIME ZONE:原樣保存時區(qū)偏移,查詢時顯示帶時區(qū)的時間
  • TIMESTAMP WITH LOCAL TIME ZONE:自動轉換為當前會話時區(qū)顯示
-- 場景:跨國會議安排
CREATE TABLE global_meetings (
    meeting_id   INT,
    topic        VARCHAR2(200),
    start_time   TIMESTAMP WITH TIME ZONE,         -- 保留原始時區(qū)
    end_time     TIMESTAMP WITH LOCAL TIME ZONE     -- 自動轉本地時區(qū)
);

-- 北京時間下午3點開會
INSERT INTO global_meetings VALUES (
    1,
    '全球技術同步會',
    TIMESTAMP '2024-06-15 15:00:00 +08:00',
    TIMESTAMP '2024-06-15 17:00:00 +08:00'
);

-- 查詢時能看到時區(qū)信息
SELECT meeting_id, topic, start_time FROM global_meetings;
-- 輸出:1 | 全球技術同步會 | 2024-06-15 15:00:00 +08:00

3.4 INTERVAL——表示"一段時間"

INTERVAL不是某個時間點,而是一段時間的長度。比如"3個月"、"2天4小時30分鐘"這種。

它有兩種形式:

-- INTERVAL YEAR TO MONTH:以"年+月"為單位
-- INTERVAL DAY TO SECOND:以"天+時+分+秒"為單位

-- 例子:2004年閏年2月29日,加4年后是哪天?
SELECT TO_DATE('29-FEB-2004', 'DD-MON-YYYY') + TO_YMINTERVAL('4-0') AS result;
-- 輸出:2008-02-29 00:00:00

-- 實際建表使用
CREATE TABLE project_schedule (
    project_name VARCHAR2(100),
    start_time   TIMESTAMP,
    buffer_time  INTERVAL DAY(3) TO SECOND(0),   -- 緩沖時間,精確到天和秒
    duration     INTERVAL YEAR TO MONTH            -- 項目周期,以年月為單位
);

INSERT INTO project_schedule VALUES (
    'ERP系統(tǒng)建設',
    TO_TIMESTAMP('2024-03-01 09:00:00', 'YYYY-MM-DD HH24:MI:SS'),
    '0 12:30:00',    -- 半天緩沖
    '1-6'            -- 1年6個月
);

SELECT project_name,
       start_time,
       buffer_time,
       duration,
       start_time + buffer_time AS adjusted_start
FROM project_schedule;

最后來個快速對照表:

類型什么時候用典型場景
DATE不需要毫秒精度生日、節(jié)假日、訂單日期
TIMESTAMP需要精確到毫秒/微秒系統(tǒng)日志、審計追蹤
TIMESTAMP WITH TIME ZONE用戶跨越多個時區(qū)國際會議、全球化系統(tǒng)
INTERVAL算時間差或設偏移項目排期、定時任務

四、大對象類型:圖片、長文、視頻往里塞

普通字符串存幾萬字還行,但如果你要存一張高清圖片或者一部視頻,那就要靠LOB(Large Object)類型了。

4.1 BLOB——二進制文件專用

BLOB專門用來存二進制格式的大文件——圖片、音頻、視頻都可以,最大能存到1GB。

CREATE TABLE media_library (
    file_id     INT,
    file_name   VARCHAR2(200),
    file_type   VARCHAR2(20),    -- image/audio/video
    file_size   INT,             -- 文件大?。ㄗ止?jié))
    file_data   BLOB             -- 實際文件內容
);

-- 插入一條記錄(實際開發(fā)中通常通過程序寫入BLOB數(shù)據(jù))
INSERT INTO media_library (file_id, file_name, file_type, file_size, file_data)
VALUES (1, 'banner.jpg', 'image', 204800, empty_blob());

4.2 CLOB與NCLOB——超長文本的歸宿

  • CLOB:用數(shù)據(jù)庫字符集存大段文本,最大1GB
  • NCLOB:用Unicode國際字符集存大段文本,最大1GB
CREATE TABLE knowledge_base (
    article_id  INT PRIMARY KEY,
    title       VARCHAR2(200),
    author      VARCHAR2(50),
    content     CLOB,            -- 文章正文,幾萬字不在話下
    summary     NCLOB,           -- Unicode格式的摘要
    created_at  DATE
);

INSERT INTO knowledge_base VALUES (
    1,
    '數(shù)據(jù)庫性能優(yōu)化實戰(zhàn)',
    '技術團隊',
    '本文詳細介紹了數(shù)據(jù)庫性能優(yōu)化的各個方面,包括索引設計、查詢優(yōu)化、緩存策略……(此處省略一萬字)',
    '從索引到緩存,全方位講解性能優(yōu)化方法',
    TO_DATE('2024-06-01', 'YYYY-MM-DD')
);

-- CLOB也能用LIKE搜索
SELECT title FROM knowledge_base WHERE content LIKE '%索引設計%';

4.3 BFILE——不存文件,只存"文件在哪"

BFILE比較特殊——它不存文件內容,只存一個指向操作系統(tǒng)文件的"指針"。而且只能讀,不能改。

-- 先創(chuàng)建一個目錄對象(相當于給文件路徑起個別名)
CREATE DIRECTORY doc_dir AS '/data/documents';

-- 建表
CREATE TABLE external_docs (
    doc_id    INT,
    doc_name  VARCHAR2(200),
    doc_ref   BFILE           -- 指向外部文件的引用
);

-- 用BFILENAME函數(shù)插入文件引用
INSERT INTO external_docs VALUES (1, '年度報告', BFILENAME('doc_dir', 'annual_report.pdf'));
INSERT INTO external_docs VALUES (2, '技術規(guī)范', BFILENAME('doc_dir', 'tech_spec.docx'));

-- 查詢時看到的是引用信息,不是文件內容
SELECT doc_id, doc_name FROM external_docs;

使用建議:BFILE適合存那些"體積大但不需要在數(shù)據(jù)庫里修改"的文件,比如歸檔的PDF、歷史掃描件等。

五、RAW類型:二進制數(shù)據(jù)"原樣搬運"

RAW類型用來存二進制數(shù)據(jù),它最實用的特點是:在不同字符集的數(shù)據(jù)庫或客戶端之間傳輸時,數(shù)據(jù)不會被"自作主張"地轉換編碼。

RAW [(size)]     -- size范圍1~32767字節(jié)
LONG RAW         -- 跟RAW一樣,但不能指定長度
CREATE TABLE raw_data (
    id         INT,
    bin_data   RAW(1024),       -- 最多1024字節(jié)的二進制數(shù)據(jù)
    signature  RAW(256)         -- 256字節(jié)的數(shù)字簽名
);

-- 用HEXTORAW把十六進制字符串轉成RAW
INSERT INTO raw_data VALUES (1, HEXTORAW('0A1B2C3D4E5F'), HEXTORAW('AABBCCDD'));

-- 用RAWTOHEX把RAW轉回十六進制查看
SELECT id, RAWTOHEX(bin_data) AS hex_data FROM raw_data;
-- 輸出:1 | 0A1B2C3D4E5F

什么時候用RAW?加密數(shù)據(jù)、通信協(xié)議數(shù)據(jù)、設備原始報文——這類"就是一串字節(jié),別給我做任何轉換"的場景。

六、JSON類型:靈活數(shù)據(jù)的存儲利器

現(xiàn)在幾乎所有應用都在用JSON——配置信息、API返回值、動態(tài)表單,到處都是。數(shù)據(jù)庫原生支持JSON,不用再把JSON當普通字符串存了。

數(shù)據(jù)庫提供了兩種JSON類型:JSONJSONB。

6.1 JSON和JSONB到底選哪個?

這是最常被問到的問題。簡單說:

  • JSON:原樣存儲,存得快,但每次查詢都要重新解析
  • JSONB:存的時候就解析成二進制,占空間稍大,但查詢快得多,還支持索引
對比項JSONJSONB
存儲方式原始文本二進制格式
空格處理原樣保留自動去掉
鍵的順序保持輸入順序自動排序
重復鍵全部保留只留最后一個
查詢速度每次要重新解析直接查,快
能建索引嗎不能能(GIN索引)

結論:絕大多數(shù)場景下,直接用JSONB就對了。

6.2 JSON基本操作

-- 創(chuàng)建一張存JSON數(shù)據(jù)的表
CREATE TABLE api_data (
    id    INT,
    jdoc  JSONB
);

-- 插入一條JSON數(shù)據(jù)
INSERT INTO api_data VALUES (1, '{
    "guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a",
    "name": "張三",
    "is_active": true,
    "score": 95.5,
    "tags": ["developer", "architect", "leader"]
}');

-- 再插一條
INSERT INTO api_data VALUES (2, '{
    "guid": "7f3b2a01-4e9c-4d2f-b8a1-6234567890ab",
    "name": "李四",
    "is_active": false,
    "score": 88.0,
    "tags": ["designer", "leader"]
}');

-- 用 -> 提取JSON對象(返回JSON類型)
-- 用 ->> 提取JSON對象(返回文本)
SELECT
    jdoc->>'name'   AS name,
    jdoc->'score'   AS score,
    jdoc->'is_active' AS active
FROM api_data;

-- 輸出:
--  name | score | active
-- ------+-------+--------
--  張三 | 95.5  | true
--  李四 | 88.0  | false

6.3 JSONB查詢:包含、存在、嵌套

JSONB的查詢能力非常強大,幾個操作符就能搞定大部分需求:

-- @> 包含查詢:tags里有沒有"leader"?
SELECT jdoc->>'name' AS name FROM api_data
WHERE jdoc @> '{"tags":["leader"]}'::jsonb;
-- 輸出:張三 和 李四 都有l(wèi)eader標簽

-- ? 存在查詢:有沒有某個鍵?
SELECT jdoc->>'name' AS name FROM api_data
WHERE jdoc ? 'is_active';
-- 輸出:兩條都有

-- ?| 任一存在:有沒有tags或者email?
SELECT jdoc->>'name' AS name FROM api_data
WHERE jdoc ?| array['tags', 'email'];

-- ?& 全部存在:是不是同時有name和score?
SELECT jdoc->>'name' AS name FROM api_data
WHERE jdoc ?& array['name', 'score'];

嵌套查詢也不在話下:

-- 更復雜的嵌套數(shù)據(jù)
INSERT INTO api_data VALUES (3, '{
    "name": "王五",
    "tags": [
        {"term": "backend", "level": "senior"},
        {"term": "cloud", "level": "expert"}
    ]
}');

-- 查找tags中包含特定term的文檔
SELECT jdoc->>'name' FROM api_data
WHERE jdoc @> '{"tags":[{"term":"backend"}]}';

6.4 給JSONB建索引,查詢飛起來

數(shù)據(jù)量一大,JSONB查詢也會變慢。這時候就得靠GIN索引了:

-- 通用GIN索引,支持 @>、?、?&、?| 操作符
CREATE INDEX idx_jsonb ON api_data USING gin (jdoc);

-- jsonb_path_ops索引:只支持@>操作符,但更小更快
CREATE INDEX idx_jsonb_path ON api_data USING gin (jdoc jsonb_path_ops);

-- 針對特定鍵的表達式索引(最精準)
CREATE INDEX idx_jsonb_tags ON api_data USING gin ((jdoc -> 'tags'));

建完索引后,包含查詢就能走索引了,速度快很多:

-- 這個查詢會走 idx_jsonb_tags 索引
SELECT jdoc->>'name', jdoc->'score' FROM api_data
WHERE jdoc -> 'tags' ? 'leader';

6.5 JSONPATH——更靈活的路徑查詢

除了基本的操作符,還可以用JSONPATH語法做更高級的查詢:

-- 用 @@ 操作符配合JSONPATH語法
SELECT jdoc->>'name' FROM api_data
WHERE jdoc @@ '$.tags[*] == "leader"';

-- 帶條件的路徑查詢
SELECT jdoc->>'name' FROM api_data
WHERE jdoc @@ '$.score ? (@ > 90)';
-- 輸出:張三(score=95.5)

七、XML類型:結構化文檔怎么存

XML在金融、政務、企業(yè)集成這些領域用得很多。相比把XML隨便塞進一個文本字段,用專門的XML類型有個好處——存儲時會自動檢查XML結構合不合法。

7.1 XML基礎用法

CREATE TABLE xml_docs (
    doc_id   INT,
    content  XML
);

-- 方式一:用XMLPARSE創(chuàng)建
INSERT INTO xml_docs VALUES (1,
    XMLPARSE(DOCUMENT '<?xml version="1.0"?>
    <book>
        <title>數(shù)據(jù)庫入門</title>
        <chapter id="1">基礎概念</chapter>
        <chapter id="2">進階技巧</chapter>
    </book>')
);

-- 方式二:直接類型轉換
INSERT INTO xml_docs VALUES (2, '<note><to>張三</to><body>明天開會</body></note>'::xml);

-- 查詢XML內容
SELECT doc_id, content FROM xml_docs;

-- 把XML轉回字符串
SELECT XMLSERIALIZE(DOCUMENT content AS text) FROM xml_docs WHERE doc_id = 1;

-- 判斷是完整文檔還是文檔片段
SELECT content IS DOCUMENT AS is_full_doc FROM xml_docs;

7.2 XMLType——更強大的XML操作

XMLType提供了一套方法,可以用XPath表達式在XML里精準定位和提取數(shù)據(jù):

CREATE TABLE xml_orders (
    order_id INT,
    order_data XMLType
);

-- 插入XML格式的訂單數(shù)據(jù)
INSERT INTO xml_orders VALUES (1, XMLType('<?xml version="1.0"?>
<Order>
    <Customer>李四</Customer>
    <Items>
        <Item sku="A001">
            <Name>鍵盤</Name>
            <Price>299</Price>
            <Qty>2</Qty>
        </Item>
        <Item sku="A002">
            <Name>鼠標</Name>
            <Price>89</Price>
            <Qty>1</Qty>
        </Item>
    </Items>
    <Total>687</Total>
</Order>'));

-- 使用XMLType的方法查詢
SELECT x.order_data FROM xml_orders x;

注意:XML類型沒有比較操作符,不能直接在上面建索引。需要快速搜索的話,要在XPath表達式上建函數(shù)索引。

八、幾何類型:坐標、區(qū)域、距離計算

這組類型可能日常業(yè)務不太常用,但在地圖應用、CAD設計、游戲開發(fā)這些場景中就非常關鍵了。

數(shù)據(jù)庫內置了7種二維幾何類型:

類型占多大干什么用怎么寫
point16字節(jié)平面上的一個點(x, y)
line32字節(jié)無限長的直線{A, B, C}
lseg32字節(jié)一段線段((x1,y1),(x2,y2))
box32字節(jié)矩形((x1,y1),(x2,y2))
path16+16n字節(jié)路徑(開放或封閉)[(x1,y1),…]或((x1,y1),…)
polygon40+16n字節(jié)多邊形((x1,y1),…)
circle24字節(jié)<(x,y),r>
-- 建一張帶幾何字段的表
CREATE TABLE locations (
    name      VARCHAR2(50),
    center    point,          -- 中心坐標
    area      polygon,        -- 區(qū)域多邊形
    boundary  circle          -- 圓形邊界
);

INSERT INTO locations VALUES (
    '總部大樓',
    '(116.397, 39.908)',                                -- 一個點
    '((116.39, 39.90), (116.40, 39.90),
      (116.40, 39.91), (116.39, 39.91))',               -- 四邊形
    '<(116.397, 39.908), 0.005>'                        -- 以點為圓心的圓
);

SELECT name, center, area, boundary FROM locations;

8.1 幾何計算示例

-- 計算兩點之間的距離
SELECT point '(1,1)' <-> point '(4,5)' AS distance;
-- 輸出:5(勾股定理:√(32+42) = 5)

-- 判斷一個點是否在矩形內
SELECT box '((0,0),(2,2))' @> point '(1,1)' AS is_inside;
-- 輸出:true

SELECT box '((0,0),(2,2))' @> point '(3,3)' AS is_inside;
-- 輸出:false

-- 計算圓的面積
SELECT area(circle '<(0,0), 5>') AS circle_area;
-- 輸出:78.5398163397448(π × 52)

-- 兩個矩形是否重疊
SELECT box '((0,0),(2,2))' && box '((1,1),(3,3))' AS overlaps;
-- 輸出:true

-- 計算兩點之間的線段中點
SELECT center(lseg '((0,0),(4,4))') AS midpoint;
-- 輸出:(2,2)

九、網絡地址類型:別再用字符串存IP了

很多人圖省事,用VARCHAR存IP地址。但字符串存IP有個大問題——你沒法判斷"192.168.1.100是不是屬于192.168.1.0/24這個網段",除非你自己寫一大堆邏輯。

用專門的inet和cidr類型,這些事數(shù)據(jù)庫幫你做了。

類型占多大存什么
cidr7或19字節(jié)IPv4/IPv6網絡地址
inet7或19字節(jié)IPv4/IPv6主機地址
macaddr6字節(jié)MAC地址
macaddr88字節(jié)MAC地址(EUI-64格式)

9.1 inet與cidr

CREATE TABLE network_assets (
    asset_name  VARCHAR2(50),
    ip_addr     inet,
    subnet      cidr
);

INSERT INTO network_assets VALUES ('web-server-1', '192.168.1.100', '192.168.1.0/24');
INSERT INTO network_assets VALUES ('db-server',    '10.0.0.5/16',    '10.0.0.0/16');
INSERT INTO network_assets VALUES ('cache-server', '172.16.5.20',    '172.16.0.0/16');

-- 檢查IP是否屬于某個網段(<< 表示"包含在")
SELECT asset_name FROM network_assets WHERE ip_addr << '192.168.1.0/24'::cidr;
-- 輸出:web-server-1

-- 獲取IP的網絡部分
SELECT network('192.168.1.100/24');
-- 輸出:192.168.1.0/24

-- 獲取主機部分
SELECT host('192.168.1.100/24');
-- 輸出:192.168.1.100

-- 判斷兩個網段是否重疊
SELECT inet '192.168.1.0/24' && inet '192.168.1.128/25' AS overlaps;
-- 輸出:true

inet和cidr的區(qū)別:inet允許"非標準"寫法(比如192.168.0.1/24,主機位不是全0),cidr則要求嚴格的網絡地址。

9.2 MAC地址

CREATE TABLE devices (
    device_id  INT,
    device_name VARCHAR2(50),
    mac        macaddr
);

-- 下面這幾種寫法都是同一個MAC地址
INSERT INTO devices VALUES (1, '服務器A', '08:00:2b:01:02:03');
INSERT INTO devices VALUES (2, '服務器B', '08-00-2b-01-02-03');
INSERT INTO devices VALUES (3, '交換機',  '08002b:010203');
INSERT INTO devices VALUES (4, '路由器',  '0800.2b01.0203');
INSERT INTO devices VALUES (5, '防火墻',  '08002b010203');

-- 查詢時統(tǒng)一輸出為冒號分隔格式
SELECT device_id, device_name, mac FROM devices;
-- 輸出全部顯示為 08:00:2b:01:02:03

-- EUI-64格式的MAC地址(8字節(jié))
INSERT INTO devices VALUES (6, '無線AP', '08:00:2b:01:02:03:04:05'::macaddr8);

-- 把48位MAC轉成EUI-64格式
SELECT macaddr8_set7bit('08:00:2b:01:02:03');
-- 輸出:0a:00:2b:ff:fe:01:02:03

十、全文搜索:讓數(shù)據(jù)庫幫你"找文章"

如果你要在大量文本中搜索關鍵詞,LIKE ‘%關鍵詞%’ 也能湊合用,但性能很差,而且沒法按相關度排序。全文搜索類型就是專門解決這個問題的。

它靠兩個類型配合工作:

  • tsvector:把文檔文本拆解、去重、排序后存儲的"詞袋"
  • tsquery:你要搜索的關鍵詞組合

10.1 tsvector——把文本變成可搜索的格式

-- 直接轉tsvector:自動去重和排序
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector;
-- 輸出:'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat'
-- 注意:重復的a和fat只出現(xiàn)一次

-- 用to_tsvector進行語言相關的處理(推薦)
SELECT to_tsvector('english', 'The Fat Rats');
-- 輸出:'fat':2 'rat':3
-- "The"被過濾(停用詞),"Fat"變成小寫"fat","Rats"變成詞干"rat"
-- 冒號后面的數(shù)字是詞在原文中的位置

10.2 tsquery——構建搜索條件

tsquery支持布爾操作符來組合搜索詞:

操作符含義例子
&AND,同時包含fat & rat
|OR,包含任一fat | cat
!NOT,不包含fat & !cat
<->緊跟在后面quick <-> fox
-- 簡單AND查詢
SELECT 'fat & rat'::tsquery;
-- 輸出:'fat' & 'rat'

-- 組合查詢
SELECT 'fat & (rat | cat)'::tsquery;
-- 輸出:'fat' & ( 'rat' | 'cat' )

-- 排除查詢
SELECT 'fat & rat & !cat'::tsquery;
-- 輸出:'fat' & 'rat' & !'cat'

-- 前綴匹配
SELECT 'super:*'::tsquery;
-- 會匹配superman、supernatural等所有以super開頭的詞

10.3 實戰(zhàn):創(chuàng)建全文搜索系統(tǒng)

-- 建表
CREATE TABLE articles (
    article_id  INT,
    title       VARCHAR2(200),
    body        TEXT
);

INSERT INTO articles VALUES (1, '數(shù)據(jù)庫性能優(yōu)化',
    '數(shù)據(jù)庫性能優(yōu)化是每個開發(fā)者的必修課。索引設計、查詢優(yōu)化、緩存策略都是關鍵技能。');
INSERT INTO articles VALUES (2, 'Python入門教程',
    'Python是一門非常適合初學者的編程語言。它的語法簡潔,社區(qū)活躍。');
INSERT INTO articles VALUES (3, '分布式數(shù)據(jù)庫架構',
    '分布式數(shù)據(jù)庫通過數(shù)據(jù)分片和復制來提高系統(tǒng)的可用性和性能。');

-- 創(chuàng)建GIN索引加速全文搜索
CREATE INDEX idx_articles_body ON articles
USING gin (to_tsvector('english', body));

-- 搜索:找出提到"database"和"performance"的文章
SELECT title FROM articles
WHERE to_tsvector('english', body) @@ to_tsquery('database & performance');

-- 搜索:找出提到"database"或"python"的文章
SELECT title FROM articles
WHERE to_tsvector('english', body) @@ to_tsquery('database | python');

-- 按相關度排序(使用ts_rank)
SELECT title, ts_rank(to_tsvector('english', body), to_tsquery('database')) AS rank
FROM articles
WHERE to_tsvector('english', body) @@ to_tsquery('database')
ORDER BY rank DESC;

十一、范圍類型:優(yōu)雅地表達"從A到B"

生活中到處都是"區(qū)間"的概念——價格區(qū)間、日期區(qū)間、年齡范圍。以前你可能用兩個字段(start和end)來表示,現(xiàn)在可以用一個范圍類型搞定,而且天然支持"是否重疊"、"是否包含"這類查詢。

11.1 內置的6種范圍類型

類型子類型說明
int4rangeinteger整數(shù)范圍
int8rangebigint大整數(shù)范圍
numrangenumeric小數(shù)范圍
tsrangetimestamp時間戳范圍(無時區(qū))
tstzrangetimestamptz時間戳范圍(帶時區(qū))
daterangedate日期范圍

11.2 范圍操作實戰(zhàn)

范圍用方括號[]表示包含邊界,用圓括號()表示不包含邊界:

-- 會議室預約系統(tǒng)
CREATE TABLE room_booking (
    room_id   INT,
    booked_by VARCHAR2(50),
    during    tsrange
);

INSERT INTO room_booking VALUES
    (101, '張三', '[2025-01-15 09:00, 2025-01-15 10:00)'),   -- 9點到10點
    (101, '李四', '[2025-01-15 10:00, 2025-01-15 11:30)'),   -- 10點到11點半
    (102, '王五', '[2025-01-15 09:30, 2025-01-15 12:00)');   -- 9點半到12點

-- 檢查101會議室有沒有時間沖突
SELECT booked_by FROM room_booking
WHERE room_id = 101
  AND during && '[2025-01-15 09:30, 2025-01-15 10:30)'::tsrange;
-- 輸出:張三(他的9:00-10:00跟9:30-10:30有重疊)

-- 包含檢查:15在不在[10,20)范圍內?
SELECT int4range(10, 20) @> 15;
-- 輸出:true

-- 重疊檢查:兩個范圍有沒有交集?
SELECT numrange(11.1, 22.2) && numrange(20.0, 30.0);
-- 輸出:true(11.1~22.2 跟 20.0~30.0 在20.0~22.2處重疊)

-- 取交集
SELECT int4range(10, 20) * int4range(15, 25);
-- 輸出:[15,20)

-- 取上界和下界
SELECT lower(int4range(10, 20)), upper(int4range(10, 20));
-- 輸出:10 | 20

-- 范圍是否為空
SELECT isempty(numrange(1, 5));
-- 輸出:false

11.3 自定義范圍類型

如果內置的幾種不夠用,你可以自己定義:

-- 創(chuàng)建一個浮點數(shù)范圍類型
CREATE TYPE floatrange AS RANGE (
    subtype = float8,
    subtype_diff = float8mi
);

-- 直接使用
SELECT '[1.234, 5.678]'::floatrange;
-- 輸出:[1.234,5.678)

-- 也可以創(chuàng)建一個時間范圍類型
CREATE FUNCTION time_subtype_diff(x time, y time) RETURNS float8 AS
$$ SELECT EXTRACT(EPOCH FROM (x - y)) $$ LANGUAGE sql STRICT IMMUTABLE;

CREATE TYPE timerange AS RANGE (
    subtype = time,
    subtype_diff = time_subtype_diff
);

-- 使用自定義時間范圍
SELECT '[11:10, 23:00]'::timerange;
-- 輸出:[11:10:00,23:00:00)

十二、其他實用類型

12.1 ROWID——每一行的"身份證號"

ROWID是數(shù)據(jù)庫給表中每一行自動分配的邏輯標識。它以23個16進制字符展示,是單調遞增的——后插入的數(shù)據(jù)ROWID一定更大。

-- 查看每一行的ROWID
SELECT ROWID, employee_id, name FROM employees WHERE employee_id <= 5;

-- 用ROWID定位特定行(比用主鍵還快)
SELECT * FROM employees WHERE ROWID = 'AAAACMAABAAAAEqAAA';

-- ROWID支持比較操作符
SELECT ROWID, name FROM employees
WHERE ROWID > 'AAAACMAABAAAAEqAAA'
ORDER BY ROWID;

12.2 用戶自定義類型

當內置類型沒法滿足你的業(yè)務模型時,可以自己定義類型:

-- 定義一個對象類型:地址
CREATE TYPE address_type AS OBJECT (
    province   VARCHAR2(50),
    city       VARCHAR2(50),
    street     VARCHAR2(200),
    post_code  CHAR(6)
);

-- 在表中使用自定義類型
CREATE TABLE customers (
    customer_id  INT,
    name         VARCHAR2(50),
    home_addr    address_type
);

-- 可變數(shù)組(Varray):一組有序元素,需指定最大數(shù)量
-- 嵌套表(Nested Table):一組無序元素

總結:一張表選對數(shù)據(jù)類型

你要存什么用這個類型常見場景
長度固定的文本CHAR手機號、郵編、編碼
長度不固定的文本VARCHAR2姓名、地址、備注
多語言文本NVARCHAR2國際化應用的界面文本
精確小數(shù)(尤其是錢)NUMBER(p,s)價格、金額、折扣率
整數(shù)INT / SMALLINTID、數(shù)量、年齡、狀態(tài)碼
科學數(shù)據(jù)、傳感器值BINARY_FLOAT / BINARY_DOUBLE溫度、氣壓、坐標值
日期(不要求毫秒)DATE生日、訂單日期
精確時間戳TIMESTAMP日志、審計記錄
跨時區(qū)時間TIMESTAMP WITH TIME ZONE全球化系統(tǒng)
大段文本CLOB / NCLOB文章、合同、日志文件
圖片、音視頻BLOB多媒體文件存儲
二進制數(shù)據(jù)RAW加密數(shù)據(jù)、協(xié)議報文
靈活結構的數(shù)據(jù)JSONB配置信息、動態(tài)屬性
XML文檔XML / XMLType金融報文、政務數(shù)據(jù)
平面坐標、區(qū)域point / polygon / circle地圖標記、區(qū)域范圍
IP地址inet / cidr網絡設備管理
MAC地址macaddr設備管理
文本關鍵詞搜索tsvector + tsquery文檔搜索、內容檢索
區(qū)間范圍各類range類型排期、定價區(qū)間

最后記住三個選類型的原則:

  1. 精確優(yōu)先:能用NUMBER就別用FLOAT,尤其是算錢的時候
  2. 夠用就好:能用SMALLINT就別用INT,能用VARCHAR2(50)就別用VARCHAR2(4000),省空間就是省性能
  3. 語義匹配:IP地址別用字符串,時間別用字符串,讓數(shù)據(jù)庫幫你做數(shù)據(jù)校驗

到此這篇關于KingbaseES數(shù)據(jù)類型從基礎CHAR到JSON/XML/幾何類型完全指南的文章就介紹到這了,更多相關KingbaseES數(shù)據(jù)類型內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

罗甸县| 维西| 宝鸡市| 临高县| 桐庐县| 旬阳县| 海伦市| 利津县| 灵川县| 古蔺县| 乐山市| 舞阳县| 长汀县| 广丰县| 扶绥县| 菏泽市| 土默特右旗| 库车县| 贵阳市| 宿州市| 尚志市| 讷河市| 景泰县| 景谷| 安龙县| 湛江市| 正蓝旗| 蒲江县| 沁源县| 新野县| 沿河| 布拖县| 垣曲县| 禹州市| 汉阴县| 阜平县| 蕲春县| 赤水市| 施秉县| 邮箱| 尚志市|