Oracle数据类型 #

一、数据类型概述 #

1.1 类型分类 #

text
Oracle数据类型
├── 数值类型
│   ├── NUMBER
│   ├── INTEGER
│   ├── FLOAT
│   ├── BINARY_FLOAT
│   └── BINARY_DOUBLE
├── 字符类型
│   ├── CHAR
│   ├── VARCHAR2
│   ├── NCHAR
│   ├── NVARCHAR2
│   └── CLOB
├── 日期时间类型
│   ├── DATE
│   ├── TIMESTAMP
│   ├── TIMESTAMP WITH TIME ZONE
│   └── INTERVAL
├── LOB类型
│   ├── CLOB
│   ├── BLOB
│   ├── NCLOB
│   └── BFILE
├── RAW类型
│   ├── RAW
│   └── LONG RAW
└── 其他类型
    ├── ROWID
    ├── UROWID
    ├── XMLTYPE
    └── JSON(21c+)

二、数值类型 #

2.1 NUMBER类型 #

sql
-- NUMBER语法
-- NUMBER(precision, scale)
-- precision:精度,总位数(1-38)
-- scale:标度,小数位数(-84-127)

-- 整数
CREATE TABLE number_examples (
    id NUMBER,              -- 无限制
    age NUMBER(3),          -- 最大999
    count_num NUMBER(10)    -- 最大10位整数
);

-- 定点数
ALTER TABLE number_examples ADD (
    salary NUMBER(10,2),    -- 最大8位整数,2位小数
    rate NUMBER(5,4)        -- 1位整数,4位小数
);

-- 负标度
ALTER TABLE number_examples ADD (
    large_num NUMBER(10,-2) -- 精确到百位
);

-- 插入数据
INSERT INTO number_examples (id, age, salary, rate, large_num)
VALUES (1, 25, 12345.67, 0.1234, 12345);
-- large_num存储:12300(四舍五入到百位)

2.2 NUMBER存储范围 #

sql
-- NUMBER存储范围
-- 正数:1 x 10^-130 到 9.999... x 10^125
-- 负数:-1 x 10^-130 到 -9.999... x 10^125
-- 零:0

-- 测试范围
SELECT 
    CAST('1E-130' AS NUMBER) AS min_positive,
    CAST('1E125' AS NUMBER) AS max_positive
FROM DUAL;

-- 精度溢出会报错
INSERT INTO number_examples (age) VALUES (1000);  -- ORA-01438

2.3 INTEGER类型 #

sql
-- INTEGER是NUMBER的子类型,存储整数
CREATE TABLE integer_examples (
    id INTEGER,
    count_val INTEGER
);

-- 等价于
CREATE TABLE integer_examples (
    id NUMBER(38),
    count_val NUMBER(38)
);

-- 插入数据
INSERT INTO integer_examples VALUES (1, 100);
INSERT INTO integer_examples VALUES (2, 100.5);  -- 四舍五入为101

2.4 FLOAT类型 #

sql
-- FLOAT是NUMBER的子类型,浮点数
CREATE TABLE float_examples (
    id NUMBER,
    value FLOAT,
    value_126 FLOAT(126)  -- 126位二进制精度
);

-- FLOAT(n):n为二进制精度(1-126)
-- FLOAT(126)约等于38位十进制精度

-- 插入数据
INSERT INTO float_examples VALUES (1, 123.456789, 123.456789);

2.5 BINARY_FLOAT和BINARY_DOUBLE #

sql
-- BINARY_FLOAT:32位单精度浮点数
-- BINARY_DOUBLE:64位双精度浮点数

CREATE TABLE binary_examples (
    id NUMBER,
    float_val BINARY_FLOAT,
    double_val BINARY_DOUBLE
);

-- 插入数据
INSERT INTO binary_examples VALUES (
    1, 
    123.456f,    -- BINARY_FLOAT后缀f
    123.456d     -- BINARY_DOUBLE后缀d
);

-- 特殊值
INSERT INTO binary_examples VALUES (
    2,
    BINARY_FLOAT_INFINITY,    -- 正无穷
    BINARY_DOUBLE_INFINITY
);

INSERT INTO binary_examples VALUES (
    3,
    BINARY_FLOAT_NAN,         -- 非数字
    BINARY_DOUBLE_NAN
);

-- 性能比较
-- BINARY_FLOAT/BINARY_DOUBLE:计算速度快
-- NUMBER:精确计算,适合金融

2.6 数值类型选择建议 #

场景 推荐类型
主键ID NUMBER(10) 或 NUMBER
年龄 NUMBER(3)
金额 NUMBER(10,2) 或 NUMBER(18,4)
百分比 NUMBER(5,4)
科学计算 BINARY_DOUBLE
计数器 INTEGER

三、字符类型 #

3.1 CHAR类型 #

sql
-- CHAR:定长字符串
-- CHAR(n):n为字符数(1-2000)

CREATE TABLE char_examples (
    code CHAR(10),        -- 10个字符
    status CHAR(1),       -- 1个字符
    flag CHAR(5) DEFAULT 'N'
);

-- 插入数据
INSERT INTO char_examples (code, status) VALUES ('ABC', 'A');
-- code存储:'ABC       '(补空格到10位)

-- 查询时注意空格
SELECT * FROM char_examples WHERE code = 'ABC';      -- 可以匹配
SELECT * FROM char_examples WHERE code = 'ABC     '; -- 可以匹配
SELECT * FROM char_examples WHERE TRIM(code) = 'ABC'; -- 去空格匹配

3.2 VARCHAR2类型 #

sql
-- VARCHAR2:变长字符串
-- VARCHAR2(n):n为字符数(1-4000)

CREATE TABLE varchar2_examples (
    name VARCHAR2(100),
    email VARCHAR2(200),
    description VARCHAR2(4000)
);

-- 插入数据
INSERT INTO varchar2_examples (name, email, description)
VALUES ('John', 'john@example.com', 'This is a description');

-- name存储:'John'(4个字符,不补空格)

-- 最大长度
-- 12c R1及之前:4000字节
-- 12c R2及之后:32767字节(需启用EXTENDED)

3.3 NCHAR和NVARCHAR2 #

sql
-- NCHAR:定长Unicode字符串(1-2000字符)
-- NVARCHAR2:变长Unicode字符串(1-4000字符)

CREATE TABLE nchar_examples (
    chinese_name NVARCHAR2(100),
    japanese_name NVARCHAR2(100),
    korean_name NVARCHAR2(100)
);

-- 插入多语言数据
INSERT INTO nchar_examples VALUES (
    '张三',
    '田中',
    '김철수'
);

-- 使用N前缀指定Unicode字符串
INSERT INTO nchar_examples VALUES (
    N'李四',
    N'佐藤',
    N'박영희'
);

3.4 字符类型对比 #

类型 最大长度 存储 说明
CHAR 2000字符 定长 不足补空格
VARCHAR2 4000字符 变长 按实际存储
NCHAR 2000字符 定长Unicode 多语言支持
NVARCHAR2 4000字符 变长Unicode 多语言支持

3.5 字符类型选择建议 #

场景 推荐类型
固定长度编码 CHAR
变长字符串 VARCHAR2
多语言支持 NVARCHAR2
长文本 CLOB

四、日期时间类型 #

4.1 DATE类型 #

sql
-- DATE:日期时间类型
-- 存储:世纪、年、月、日、时、分、秒

CREATE TABLE date_examples (
    id NUMBER,
    birth_date DATE,
    hire_date DATE,
    create_time DATE DEFAULT SYSDATE
);

-- 插入数据
INSERT INTO date_examples (id, birth_date, hire_date)
VALUES (1, TO_DATE('1990-05-15', 'YYYY-MM-DD'), SYSDATE);

-- 使用日期字面量
INSERT INTO date_examples (id, birth_date, hire_date)
VALUES (2, DATE '1990-05-15', DATE '2024-01-15');

-- 日期范围:公元前4712年1月1日 到 公元9999年12月31日

4.2 DATE函数 #

sql
-- 当前日期
SELECT SYSDATE FROM DUAL;
SELECT CURRENT_DATE FROM DUAL;

-- 日期计算
SELECT SYSDATE + 1 FROM DUAL;      -- 加1天
SELECT SYSDATE - 1 FROM DUAL;      -- 减1天
SELECT SYSDATE + 1/24 FROM DUAL;   -- 加1小时
SELECT SYSDATE + 1/1440 FROM DUAL; -- 加1分钟

-- 日期函数
SELECT 
    ADD_MONTHS(SYSDATE, 1) AS next_month,
    LAST_DAY(SYSDATE) AS last_day,
    MONTHS_BETWEEN(SYSDATE, hire_date) AS months,
    NEXT_DAY(SYSDATE, 'MONDAY') AS next_monday
FROM date_examples;

-- 提取日期部分
SELECT 
    EXTRACT(YEAR FROM SYSDATE) AS year,
    EXTRACT(MONTH FROM SYSDATE) AS month,
    EXTRACT(DAY FROM SYSDATE) AS day
FROM DUAL;

-- 日期格式化
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;
SELECT TO_CHAR(SYSDATE, 'YYYY"年"MM"月"DD"日"') FROM DUAL;

4.3 TIMESTAMP类型 #

sql
-- TIMESTAMP:时间戳,包含小数秒

CREATE TABLE timestamp_examples (
    id NUMBER,
    create_time TIMESTAMP,
    update_time TIMESTAMP(6)  -- 6位小数秒
);

-- 插入数据
INSERT INTO timestamp_examples (id, create_time)
VALUES (1, TO_TIMESTAMP('2024-01-15 10:30:45.123456', 'YYYY-MM-DD HH24:MI:SS.FF6'));

-- 使用时间戳字面量
INSERT INTO timestamp_examples (id, create_time)
VALUES (2, TIMESTAMP '2024-01-15 10:30:45.123456');

-- 当前时间戳
SELECT SYSTIMESTAMP FROM DUAL;
SELECT CURRENT_TIMESTAMP FROM DUAL;

-- 时间戳格式化
SELECT TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.FF6') FROM DUAL;

4.4 TIMESTAMP WITH TIME ZONE #

sql
-- TIMESTAMP WITH TIME ZONE:带时区的时间戳

CREATE TABLE timezone_examples (
    id NUMBER,
    event_time TIMESTAMP WITH TIME ZONE,
    local_time TIMESTAMP WITH LOCAL TIME ZONE
);

-- 插入数据
INSERT INTO timezone_examples (id, event_time)
VALUES (1, TIMESTAMP '2024-01-15 10:30:00 +08:00');

-- 查询时区信息
SELECT 
    event_time,
    EXTRACT(TIMEZONE_HOUR FROM event_time) AS tz_hour,
    EXTRACT(TIMEZONE_MINUTE FROM event_time) AS tz_minute
FROM timezone_examples;

-- 时区转换
SELECT 
    event_time AT TIME ZONE 'UTC' AS utc_time,
    event_time AT TIME ZONE 'America/New_York' AS ny_time
FROM timezone_examples;

4.5 INTERVAL类型 #

sql
-- INTERVAL YEAR TO MONTH:年月间隔
-- INTERVAL DAY TO SECOND:日时分秒间隔

CREATE TABLE interval_examples (
    id NUMBER,
    year_month INTERVAL YEAR(2) TO MONTH,
    day_second INTERVAL DAY(2) TO SECOND(6)
);

-- 插入数据
INSERT INTO interval_examples (id, year_month, day_second)
VALUES (
    1,
    INTERVAL '1-6' YEAR TO MONTH,      -- 1年6个月
    INTERVAL '2 12:30:45.123456' DAY TO SECOND  -- 2天12小时30分45秒
);

-- 使用INTERVAL计算
SELECT 
    SYSDATE + INTERVAL '1' YEAR AS next_year,
    SYSDATE + INTERVAL '6' MONTH AS six_months_later,
    SYSDATE + INTERVAL '7' DAY AS next_week
FROM DUAL;

-- 计算两个日期的间隔
SELECT 
    (TO_DATE('2024-12-31', 'YYYY-MM-DD') - SYSDATE) DAY TO SECOND AS remaining
FROM DUAL;

4.6 日期时间类型选择建议 #

场景 推荐类型
出生日期 DATE
创建时间 DATE 或 TIMESTAMP
精确计时 TIMESTAMP
跨时区应用 TIMESTAMP WITH TIME ZONE
时间段计算 INTERVAL

五、LOB类型 #

5.1 CLOB类型 #

sql
-- CLOB:字符大对象,存储大文本

CREATE TABLE clob_examples (
    id NUMBER PRIMARY KEY,
    title VARCHAR2(200),
    content CLOB
);

-- 插入数据
INSERT INTO clob_examples (id, title, content)
VALUES (1, '文章标题', '这是一篇很长的文章内容...');

-- 使用EMPTY_CLOB()
INSERT INTO clob_examples (id, title, content)
VALUES (2, '文章标题2', EMPTY_CLOB());

-- 更新CLOB
UPDATE clob_examples 
SET content = '更新后的内容'
WHERE id = 2;

-- 读取CLOB
SELECT id, title, DBMS_LOB.SUBSTR(content, 100, 1) AS content_preview
FROM clob_examples;

-- CLOB最大大小:4GB * 数据库块大小

5.2 BLOB类型 #

sql
-- BLOB:二进制大对象,存储图片、文件等

CREATE TABLE blob_examples (
    id NUMBER PRIMARY KEY,
    file_name VARCHAR2(100),
    file_data BLOB,
    file_size NUMBER
);

-- 插入空BLOB
INSERT INTO blob_examples (id, file_name, file_data, file_size)
VALUES (1, 'image.png', EMPTY_BLOB(), 0);

-- 使用PL/SQL写入BLOB
DECLARE
    v_blob BLOB;
    v_file BFILE;
BEGIN
    INSERT INTO blob_examples (id, file_name, file_data)
    VALUES (1, 'image.png', EMPTY_BLOB())
    RETURNING file_data INTO v_blob;
    
    v_file := BFILENAME('FILE_DIR', 'image.png');
    DBMS_LOB.FILEOPEN(v_file);
    DBMS_LOB.LOADFROMFILE(v_blob, v_file, DBMS_LOB.GETLENGTH(v_file));
    DBMS_LOB.FILECLOSE(v_file);
    
    COMMIT;
END;
/

5.3 NCLOB类型 #

sql
-- NCLOB:Unicode字符大对象

CREATE TABLE nclob_examples (
    id NUMBER PRIMARY KEY,
    title NVARCHAR2(200),
    content NCLOB
);

-- 插入多语言大文本
INSERT INTO nclob_examples (id, title, content)
VALUES (1, '标题', '多语言内容...');

5.4 BFILE类型 #

sql
-- BFILE:外部文件引用,文件存储在文件系统中

-- 创建目录对象
CREATE DIRECTORY FILE_DIR AS '/data/files';

CREATE TABLE bfile_examples (
    id NUMBER PRIMARY KEY,
    file_name VARCHAR2(100),
    file_path BFILE
);

-- 插入BFILE引用
INSERT INTO bfile_examples (id, file_name, file_path)
VALUES (1, 'document.pdf', BFILENAME('FILE_DIR', 'document.pdf'));

-- 检查文件是否存在
SELECT id, file_name, DBMS_LOB.FILEEXISTS(file_path) AS exists_flag
FROM bfile_examples;

5.5 LOB类型对比 #

类型 说明 最大大小 存储位置
CLOB 字符大对象 4GB*块大小 数据库内
BLOB 二进制大对象 4GB*块大小 数据库内
NCLOB Unicode大对象 4GB*块大小 数据库内
BFILE 外部文件引用 4GB 文件系统

六、RAW类型 #

6.1 RAW类型 #

sql
-- RAW:原始二进制数据
-- RAW(n):n为字节数(1-2000)

CREATE TABLE raw_examples (
    id NUMBER PRIMARY KEY,
    raw_data RAW(100),
    guid RAW(16)
);

-- 插入数据
INSERT INTO raw_examples (id, raw_data, guid)
VALUES (1, '48656C6C6F', SYS_GUID());

-- 生成GUID
SELECT SYS_GUID() FROM DUAL;
-- 结果:类似 6F9619FF8B86D011B42D00C04FC964FF

-- RAW转字符串
SELECT UTL_RAW.CAST_TO_VARCHAR2(raw_data) FROM raw_examples;
-- 结果:Hello

-- 字符串转RAW
SELECT UTL_RAW.CAST_TO_RAW('Hello') FROM DUAL;
-- 结果:48656C6C6F

6.2 RAW函数 #

sql
-- 获取RAW长度
SELECT UTL_RAW.LENGTH(UTL_RAW.CAST_TO_RAW('Hello')) FROM DUAL;

-- RAW拼接
SELECT UTL_RAW.CONCAT(
    UTL_RAW.CAST_TO_RAW('Hello'),
    UTL_RAW.CAST_TO_RAW(' ')
) FROM DUAL;

-- RAW转十六进制字符串
SELECT RAWTOHEX(UTL_RAW.CAST_TO_RAW('Hello')) FROM DUAL;

-- 十六进制字符串转RAW
SELECT HEXTORAW('48656C6C6F') FROM DUAL;

七、特殊类型 #

7.1 ROWID和UROWID #

sql
-- ROWID:行的物理地址

CREATE TABLE rowid_examples (
    id NUMBER PRIMARY KEY,
    name VARCHAR2(50)
);

-- 查看ROWID
SELECT ROWID, id, name FROM rowid_examples;

-- 通过ROWID查询(最快)
SELECT * FROM rowid_examples WHERE ROWID = 'AAASdqAAEAAAAInAAA';

-- ROWID组成
-- OOOOOO:数据对象号
-- FFF:相对文件号
-- BBBBBB:数据块号
-- RRR:行号

-- 解析ROWID
SELECT 
    DBMS_ROWID.ROWID_OBJECT(ROWID) AS object_id,
    DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID) AS file_no,
    DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID) AS block_no,
    DBMS_ROWID.ROWID_ROW_NUMBER(ROWID) AS row_no
FROM rowid_examples;

-- UROWID:通用ROWID,支持索引组织表

7.2 XMLTYPE类型 #

sql
-- XMLTYPE:存储XML数据

CREATE TABLE xml_examples (
    id NUMBER PRIMARY KEY,
    xml_data XMLTYPE
);

-- 插入XML数据
INSERT INTO xml_examples (id, xml_data)
VALUES (
    1,
    XMLTYPE('<employee><id>1</id><name>John</name></employee>')
);

-- 查询XML
SELECT 
    id,
    XMLTYPE.getclobval(xml_data) AS xml_string
FROM xml_examples;

-- 提取XML节点
SELECT 
    id,
    EXTRACTVALUE(xml_data, '/employee/name') AS name
FROM xml_examples;

-- 使用XMLTable
SELECT 
    x.id AS emp_id,
    x.name AS emp_name
FROM xml_examples e,
XMLTABLE('/employee' PASSING e.xml_data
    COLUMNS 
        id NUMBER PATH 'id',
        name VARCHAR2(50) PATH 'name'
) x;

7.3 JSON类型(21c+) #

sql
-- JSON类型:存储JSON数据(Oracle 21c+)

CREATE TABLE json_examples (
    id NUMBER PRIMARY KEY,
    json_data JSON
);

-- 插入JSON数据
INSERT INTO json_examples (id, json_data)
VALUES (
    1,
    '{"name": "John", "age": 30, "skills": ["Oracle", "SQL"]}'
);

-- 查询JSON
SELECT 
    id,
    json_data.name AS name,
    json_data.age AS age
FROM json_examples;

-- JSON函数
SELECT 
    JSON_VALUE(json_data, '$.name') AS name,
    JSON_QUERY(json_data, '$.skills') AS skills
FROM json_examples;

-- JSON条件
SELECT * FROM json_examples
WHERE json_data.age > 25;

-- JSON_EXISTS
SELECT * FROM json_examples
WHERE JSON_EXISTS(json_data, '$.skills');

八、类型转换 #

8.1 隐式转换 #

sql
-- 字符串转数字
SELECT '123' + 10 FROM DUAL;  -- 133

-- 数字转字符串
SELECT 'ID: ' || 123 FROM DUAL;  -- ID: 123

-- 字符串转日期
SELECT * FROM employees 
WHERE hire_date > '2020-01-01';  -- 隐式转换

-- 不推荐依赖隐式转换,可能导致性能问题

8.2 显式转换 #

sql
-- TO_CHAR:转换为字符串
SELECT 
    TO_CHAR(12345.67, '999,999.99') AS formatted_number,
    TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') AS formatted_date
FROM DUAL;

-- TO_NUMBER:转换为数字
SELECT TO_NUMBER('12345.67', '99999.99') FROM DUAL;

-- TO_DATE:转换为日期
SELECT TO_DATE('2024-01-15', 'YYYY-MM-DD') FROM DUAL;

-- TO_TIMESTAMP:转换为时间戳
SELECT TO_TIMESTAMP('2024-01-15 10:30:45', 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;

-- CAST:通用转换
SELECT 
    CAST(123 AS VARCHAR2(10)) AS str,
    CAST('123' AS NUMBER) AS num,
    CAST(SYSDATE AS TIMESTAMP) AS ts
FROM DUAL;

8.3 转换函数对照表 #

源类型 目标类型 函数
NUMBER VARCHAR2 TO_CHAR
DATE VARCHAR2 TO_CHAR
TIMESTAMP VARCHAR2 TO_CHAR
VARCHAR2 NUMBER TO_NUMBER
VARCHAR2 DATE TO_DATE
VARCHAR2 TIMESTAMP TO_TIMESTAMP
任意 任意 CAST

九、数据类型选择建议 #

9.1 数值类型选择 #

场景 推荐类型
主键 NUMBER(10) 或 NUMBER
金额 NUMBER(18,4)
百分比 NUMBER(5,4)
数量 NUMBER(10)
科学计算 BINARY_DOUBLE

9.2 字符类型选择 #

场景 推荐类型
固定长度编码 CHAR
变长字符串 VARCHAR2
多语言支持 NVARCHAR2
长文本 CLOB

9.3 日期类型选择 #

场景 推荐类型
出生日期 DATE
创建时间 DATE
精确计时 TIMESTAMP
跨时区 TIMESTAMP WITH TIME ZONE

十、总结 #

数据类型选择要点:

类型 选择原则
数值 根据精度需求选择
字符 定长用CHAR,变长用VARCHAR2
日期 一般用DATE,精确用TIMESTAMP
大对象 文本用CLOB,二进制用BLOB

下一步,让我们学习表空间管理!

最后更新:2026-03-27