精确数值类型
这类类型用于存储精确的数值,不会发生舍入误差,非常适合金融、金额等对精度要求极高的场景。
DECIMAL_ENHANCED 决定,标度不应大于其精度。当 DECIMAL_ENHANCED=1,缺省精度为 40;当 DECIMAL_ENHANCED=0,缺省精度为 38。DECIMAL_ENHANCED 参数,如果其为1,在精度和标度都为0的情况下精度可以到40。近似数值类型
这类类型基于 IEEE 754 标准,存储的是浮点数的近似值,适合科学计算、统计等对绝对精度要求不高但需要处理极大或极小数值范围的场景。
FLOAT§
REAL
DOUBLE PRECISION
DOUBLE§
整数类型
用于存储没有小数部分的数值。
SMALLINT
INTEGER / INT
BIGINT
TINYINT
CHAR
VARCHAR(n) / VARCHAR2(n)
TIMESTAMP WITH TIME ZONE 和 WITH LOCAL TIME ZONE 用于时区处理,但原生的 TIMESTAMP/DATETIME 不存储时区信息。1. CREATE TABLE
-- 建表语句示例
CREATE TABLE IF NOT EXISTS DM_TEST_EMPLOYEE
(
EMP_ID INT NOT NULL,
EMP_NAME VARCHAR(100) NOT NULL,
SALARY DECIMAL(12, 2) DEFAULT 0,
STATUS CHAR(1) DEFAULT '1',
CREATE_TIME TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT PK_DM_TEST_EMPLOYEE --主键约束
PRIMARY KEY (EMP_ID),
CONSTRAINT UK_DM_TEST_EMP_NAME --唯一约束
UNIQUE (EMP_NAME),
CONSTRAINT CK_DM_TEST_EMP_SALARY --检查约束,工资必须大于等于0
CHECK (SALARY >= 0),
CONSTRAINT CK_DM_TEST_EMP_STATUS --检查约束,状态只能为0或1
CHECK (STATUS IN ('0', '1'))
)
STORAGE --存储参数
(
INITIAL 1, --初始分配一个簇
NEXT 1, --当分配空间不足时再分配一个簇
MINEXTENTS 1, --至少保留一个簇
FILLFACTOR 80, --表示数据插入页时,目标填充比例为 80%,预留约 20% 的页内空间供后续更新使用
ON MAIN --表存放在 MIAN 表空间中
CLUSTERBTR --使用索引组织表(默认),堆表(NOBRANCH)一般不建议使用,性能方面远远不如索引组织表。
);
约束定义
约束用于保证表中数据的完整性,可以写成列级约束或表级约束。列级约束在列的定义之后;表级约束在所有列定义之后,用逗号单独分离。
存储参数
表空间指定
两种方法不能同时使用。
注释添加
建表后通过 COMMENT ON添加。如果已经有注释了再添加注释会覆盖。
COMMENT ON TABLE DM_TEST_EMPLOYEE IS '员工基本信息表';
COMMENT ON COLUMN DM_TEST_EMPLOYEE.EMP_ID
IS '员工唯一编号';
临时表
DM8 支持全局临时表。全局临时表具有以下特点:
事务级临时表
CREATE GLOBAL TEMPORARY TABLE DM_TMP_EMPLOYEE
(
EMP_ID INT,
EMP_NAME VARCHAR(100),
AMOUNT DECIMAL(12,2)
)
ON COMMIT DELETE ROWS;
ON COMMIT DELETE ROWS 表示:
COMMIT 后清空数据;ROLLBACK 后也会清空相应临时数据;提交事务之前,可以查询到数据。

提交事务之后,数据被清除。

会话级临时表
CREATE GLOBAL TEMPORARY TABLE DM_TMP_EMPLOYEE_SESSION
(
EMP_ID INT,
EMP_NAME VARCHAR(100),
AMOUNT DECIMAL(12,2)
)
ON COMMIT PRESERVE ROWS;
ON COMMIT PRESERVE ROWS 表示:
COMMIT 后仍保留数据;提交之后同一会话可以查询到数据

不同会话无法查询到数据

2. ALTER TABLE
ALTER TABLE [模式名.]表名 修改操作;
字段增删改
增加字段:
ALTER TABLE EMPLOYEE
ADD COLUMN PHONE VARCHAR(30);
一次增加多个字段:
ALTER TABLE EMPLOYEE
ADD (ADDRESS VARCHAR(200), AGE INT);
删除字段:
ALTER TABLE EMPLOYEE
DROP COLUMN PHONE;
级联删除相关依赖:
ALTER TABLE EMPLOYEE
DROP COLUMN PHONE CASCADE;
修改字段类型或长度:
ALTER TABLE EMPLOYEE
MODIFY EMP_NAME VARCHAR(200);
设置或删除默认值:
ALTER TABLE EMPLOYEE
ALTER COLUMN STATUS SET DEFAULT '1';
ALTER TABLE EMPLOYEE
ALTER COLUMN STATUS DROP DEFAULT;
设置是否允许空值:
ALTER TABLE EMPLOYEE
ALTER COLUMN STATUS SET NOT NULL;
ALTER TABLE EMPLOYEE
ALTER COLUMN STATUS SET NULL;
可能的影响:
NULL 或默认值。NOT NULL:已有数据存在 NULL 时操作失败。约束增删
增加主键:
ALTER TABLE EMPLOYEE
ADD CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMP_ID);
增加唯一约束:
ALTER TABLE EMPLOYEE
ADD CONSTRAINT UK_EMPLOYEE_NO UNIQUE (EMP_NO);
增加外键:
ALTER TABLE EMPLOYEE
ADD CONSTRAINT FK_EMPLOYEE_DEPT
FOREIGN KEY (DEPT_ID)
REFERENCES DEPARTMENT(DEPT_ID);
增加检查约束:
ALTER TABLE EMPLOYEE
ADD CONSTRAINT CK_EMPLOYEE_SALARY
CHECK (SALARY >= 0);
删除约束:
ALTER TABLE EMPLOYEE
DROP CONSTRAINT FK_EMPLOYEE_DEPT;
删除主键:
ALTER TABLE EMPLOYEE
DROP PRIMARY KEY;
可能的影响:
CASCADE 可能同时删除相关引用约束。表名、字段名重命名
修改表名:
ALTER TABLE EMPLOYEE
RENAME TO EMPLOYEE_INFO;
修改字段名:
ALTER TABLE EMPLOYEE_INFO
RENAME COLUMN EMP_NAME TO EMPLOYEE_NAME;
修改约束名:
ALTER TABLE EMPLOYEE_INFO
RENAME CONSTRAINT UK_EMPLOYEE_NO TO UK_EMP_NO;
影响:
表属性修改
移动表空间:
ALTER TABLE EMPLOYEE
MOVE TABLESPACE BUSINESS_TS;
设置并行度:
--数据库对这张表执行全表扫描、创建索引、数据加载等操作时,会被允许最多使用 4 个工作线程来并行处理。
--需要开启PARALLEL_POLICY 参数来生效(默认0关闭;1并行,配置生效;2手动HINT模式)
ALTER TABLE EMPLOYEE PARALLEL 4;
ALTER TABLE EMPLOYEE NOPARALLEL;
设置只读或读写:
ALTER TABLE EMPLOYEE READ ONLY;
ALTER TABLE EMPLOYEE READ WRITE;
启用或禁用触发器:
ALTER TABLE EMPLOYEE ENABLE ALL TRIGGERS;
ALTER TABLE EMPLOYEE DISABLE ALL TRIGGERS;
可能的影响:
ROWID 可能改变。3.DROP TABLE
标准删除语法
DROP TABLE [IF EXISTS] [模式名.]表名 [RESTRICT | CASCADE];
示例:
DROP TABLE EMPLOYEE;
表不存在时不报错:
DROP TABLE IF EXISTS EMPLOYEE;
限制删除:
DROP TABLE EMPLOYEE RESTRICT;
级联处理依赖:
DROP TABLE EMPLOYEE CASCADE;
说明:
RESTRICT:默认方式。存在视图或外键依赖时拒绝删除。CASCADE:删除相关引用约束;是否删除依赖视图还受 DROP_CASCADE_VIEW 参数影响。PURGE
回收站清理,默认不开启,需要开启 RECYCLEBIN,为0时关闭,1仅DROP进入回收站,2 DROP和TRUNCATE都会进入回收站。 (静态参数,需要重启数据库生效)
DROP TABLE EMPLOYEE;
PURGE TABLE EMPLOYEE;
清空当前用户回收站:
PURGE RECYCLEBIN;
DBA 清空数据库回收站:
PURGE DBA_RECYCLEBIN;
作用:
适用场景:
如果存在误删风险,不建议立即 PURGE。在回收站功能开启时,可以尝试以下命令来恢复被DROP的表。
FLASHBACK TABLE EMPLOYEE TO BEFORE DROP;
被依赖对象的处理策略
视图
推荐先查看并保存视图定义,再显式处理:
DROP VIEW V_EMPLOYEE;
DROP TABLE EMPLOYEE RESTRICT;
也可以使用:
DROP TABLE EMPLOYEE CASCADE;
但依赖视图是否被自动删除受 DROP_CASCADE_VIEW 参数影响,因此生产环境更推荐显式删除和重建视图。
外键
建议先删除外键约束:
ALTER TABLE ORDER_INFO
DROP CONSTRAINT FK_ORDER_EMPLOYEE;
DROP TABLE EMPLOYEE RESTRICT;
使用 CASCADE 时,通常删除的是引用约束,而不是直接删除子表及其数据。
存储过程、函数和触发器
ALTER PROCEDURE P_EMPLOYEE_QUERY COMPILE;
ALTER FUNCTION F_EMPLOYEE_COUNT COMPILE;
ALTER TRIGGER TRG_EMPLOYEE COMPILE;
删除表后,引用该表的程序对象可能失效或在执行时报错。建议:
动态 SQL 中的表名可能无法通过数据库依赖关系自动发现,还需要检查应用程序代码。
TRUNCATE TABLE
快速、高效地清空一个表的数据。通过直接释放整个表的数据页,不可回滚,保留结构。
可以闪回,但是需要将RECYCLEBIN 的值设为2(1无法将其放到回收站里)。
| 特性维度 | TRUNCATE TABLE (DDL) | DELETE (DML) |
|---|---|---|
| 命令类型 | 数据定义语言(DDL) | 数据操纵语言(DML) |
| 事务处理 | 无法回滚。执行时会隐式提交事务,一旦执行,数据永久删除。可通过闪回技术(需开启回收站)恢复。 | 支持回滚。在事务中可以执行ROLLBACK恢复数据。 |
| 执行原理 | 释放整个表的数据页,不逐行操作,所以极快。 | 逐行删除,并记录详细日志用于回滚,所以速度较慢。 |
| 触发器响应 | 不触发ON DELETE触发器。 | 会触发ON DELETE触发器。 |
| 空间回收 | 立即回收表空间,表空间使用率会下降。但操作系统层面的磁盘文件大小不会自动缩小。 | 不立即回收。被删行的空间标记为可复用,但表空间使用率不会立刻下降。实际物理释放受UNDO_RETENTION参数影响,需等待回滚段清理。 |
| 执行速度 | 非常快,尤其适合清空大表。 | 慢,数据量大时会产生大量日志,效率低。 |
CREATE INDEX
普通 B 树索引
CREATE INDEX hr.idx_emp_name
ON hr.emp (ename)
TABLESPACE idx_space; -- 指定存储场景
适用场景:
>、<、BETWEEN;WHERE、JOIN、ORDER BY 条件的列。不适合:
唯一索引
CREATE UNIQUE INDEX idx_emp_no
ON emp (emp_no);
唯一索引要求索引键值不能重复,可以同时提高查询性能并保证数据唯一性。
适用场景:
组合唯一索引:
CREATE UNIQUE INDEX idx_order_customer
ON orders (customer_id, order_no);
说明:主键约束和唯一约束通常会自动创建相应的唯一索引,因此不应重复创建功能相同的索引。
位图索引
CREATE BITMAP INDEX idx_emp_gender
ON emp (gender);
位图索引适合取值数量少、重复值多的列,例如:
不适合:
INSERT、UPDATE、DELETE 的 OLTP 表;函数索引
函数索引可以建立在函数或表达式上:
CREATE INDEX idx_emp_upper_name
ON emp (UPPER(ename));
查询时应尽量使用与索引表达式一致的写法:
SELECT *
FROM emp
WHERE UPPER(ename) = 'ZHANGSAN';
表达式索引示例:
CREATE INDEX idx_order_amount
ON orders (quantity * price);
对应查询:
SELECT *
FROM orders
WHERE quantity * price > 1000;
适用场景:
注意事项:
SYSDATE、RAND 等每次结果可能不同的函数;组合索引
组合索引也称复合索引,在多个列上建立一个索引:
CREATE INDEX idx_order_customer_date
ON orders (customer_id, order_date);
也可以指定排序方向:
CREATE INDEX idx_order_status_date
ON orders (status ASC, order_date DESC);
适用场景:
组合索引本质上仍是 B+ 树索引,只是索引键由多个列组成。
全文索引
全文检索专门用于处理非结构化文本数据,通过建立倒排索引实现高效的关键词定位。
CREATE CONTEXT INDEX cti_article_content
ON articles (content)
LEXER CHINESE_LEXER;
指定创建后立即进行全文索引填充:
CREATE CONTEXT INDEX cti_article_content
ON articles (content)
LEXER CHINESE_LEXER
SYNC;
提交事务后自动增量更新:
CREATE CONTEXT INDEX cti_article_content
ON articles (content)
LEXER CHINESE_LEXER
SYNC TRANSACTION;
支持的分词器包括:
CHINESE_LEXER --中文最小分词 :
CHINESE_VGRAM_LEXER --机械双字分词
CHINESE_FP_LEXER --中文最多分词
ENGLISH_LEXER --英文分词
DEFAULT_LEXER --默认分词(中文最小分词)

全文检索示例:
SELECT *
FROM articles
WHERE CONTAINS(content, '数据库');
适用场景:
全文索引支持的列类型包括 CHAR、VARCHAR、VARCHAR2、LONGVARCHAR、TEXT 和 CLOB。全文索引创建后需要进行完全更新或增量更新,填充完成后才能正常使用。

索引维护
查看索引信息
可以查询用户索引视图:
SELECT TABLE_NAME,
INDEX_NAME,
STATUS,
VISIBILITY
FROM SYS.USER_INDEXES;
查看索引定义:
SELECT INDEXDEF(index_id, 1);
其中 INDEXDEF 的第一个参数是索引 ID,可从系统视图中获得。
重建索引
ALTER INDEX idx_emp_name REBUILD;
在线重建:
ALTER INDEX idx_emp_name REBUILD ONLINE;
重建索引常用于:
UNUSABLE 后恢复;生产环境重建时应结合锁等待、并发访问和维护窗口选择普通重建或在线重建。
禁用索引
ALTER INDEX idx_emp_name UNUSABLE;
设置为 UNUSABLE 后:
REBUILD 恢复。恢复索引:
ALTER INDEX idx_emp_name REBUILD;
隐藏和显示索引
如果只是希望测试“不使用某个索引”时的执行计划,建议使用 INVISIBLE,而不是 UNUSABLE:
ALTER INDEX idx_emp_name INVISIBLE;
恢复可见:
ALTER INDEX idx_emp_name VISIBLE;
二者区别:
| 操作 | 执行计划 | DML 是否维护索引 |
|---|---|---|
UNUSABLE |
不使用 | 通常不维护 |
INVISIBLE |
默认不使用 | 仍然维护 |
因此:
UNUSABLE,但必须评估约束和业务影响;INVISIBLE;INVISIBLE 不等于删除索引。索引使用监控
开启索引使用监控:
ALTER INDEX idx_emp_name MONITORING USAGE;
关闭监控:
ALTER INDEX idx_emp_name NOMONITORING USAGE;
查看监控信息:
SELECT *
FROM SYS.V$OBJECT_USAGE;
可以根据业务高峰期的监控结果,识别长期未使用的索引,再结合 SQL、执行计划和业务需求决定是否删除。
删除普通索引
DROP INDEX idx_emp_name;
删除前应确认:
全文索引使用专用删除语法:
DROP CONTEXT INDEX cti_article_content;
索引使用规范
组合索引的最左前缀原则
假设创建索引:
CREATE INDEX idx_a_b_c
ON t (a, b, c);
该索引的有效前缀依次为:
(a)
(a, b)
(a, b, c)
通常可以有效支持:
WHERE a = 1; WHERE a = 1 AND b = 2; WHERE a = 1 AND b = 2 AND c = 3; WHERE a = 1 AND b > 2;
通常不能充分利用该索引的情况:
WHERE b = 2; WHERE c = 3; WHERE b = 2 AND c = 3;
设计原则:
索引选择性与性能
索引选择性可简单理解为:
选择性 = 不同值数量 ÷ 总行数
选择性越高,索引过滤后的结果集越小,索引通常越有价值。
示例:
| 列 | 数据特点 | 选择性 | 通常适合 |
|---|---|---|---|
| 员工编号 | 基本不重复 | 高 | B 树、唯一索引 |
| 手机号 | 基本不重复 | 高 | B 树、唯一索引 |
| 性别 | 只有少数几种值 | 低 | 位图索引或不建普通索引 |
| 是否删除 | 只有 0/1 | 很低 | 位图索引、组合索引中的辅助列 |
| 状态 | 几种固定状态 | 较低 | 视查询比例选择 B 树或位图 |
但选择性并不是唯一标准:
因此应结合:
EXPLAIN
SELECT ...
FROM ...;
以及实际执行耗时、返回行数和统计信息综合判断。
常用操作
-- 普通 B 树索引
CREATE INDEX idx_t_a ON t(a);
-- 唯一索引
CREATE UNIQUE INDEX idx_t_code ON t(code);
-- 位图索引
CREATE BITMAP INDEX idx_t_status ON t(status);
-- 函数索引
CREATE INDEX idx_t_upper_name ON t(UPPER(name));
-- 组合索引
CREATE INDEX idx_t_a_b_c ON t(a, b, c);
-- 全文索引
CREATE CONTEXT INDEX cti_t_content
ON t(content)
LEXER CHINESE_LEXER
SYNC;
-- 重建索引
ALTER INDEX idx_t_a REBUILD;
-- 在线重建
ALTER INDEX idx_t_a REBUILD ONLINE;
-- 设置索引无效
ALTER INDEX idx_t_a UNUSABLE;
-- 恢复索引有效
ALTER INDEX idx_t_a REBUILD;
-- 隐藏索引
ALTER INDEX idx_t_a INVISIBLE;
-- 恢复可见
ALTER INDEX idx_t_a VISIBLE;
-- 开启使用监控
ALTER INDEX idx_t_a MONITORING USAGE;
-- 删除普通索引
DROP INDEX idx_t_a;
-- 删除全文索引
DROP CONTEXT INDEX cti_t_content;
CREATE VIEW:普通视图与物化视图
普通视图只保存查询定义,不保存数据;查询时实时访问基表。物化视图保存查询结果,可通过刷新保持与基表同步,适合报表和汇总查询。
-- 普通视图
CREATE [OR REPLACE] VIEW [模式名.]V_EMPLOYEE AS
SELECT EMP_ID, EMP_NAME, DEPT_ID, SALARY
FROM EMPLOYEE
WHERE STATUS = '1';
-- 物化视图(DM 版本支持的语法以实际版本手册为准)
CREATE MATERIALIZED VIEW [模式名.]MV_DEPT_SALARY
BUILD IMMEDIATE
REFRESH COMPLETE ON DEMAND
AS
SELECT DEPT_ID, SUM(SALARY) AS TOTAL_SALARY
FROM EMPLOYEE
GROUP BY DEPT_ID;
普通视图适合统一查询接口、字段屏蔽和权限隔离;物化视图适合复杂聚合、跨表报表和读多写少场景。物化视图需要额外存储空间,并要设计刷新时机;BUILD IMMEDIATE 创建时立即生成数据,ON DEMAND 表示由人工或任务触发刷新。
ALTER VIEW / DROP VIEW
-- 编译视图
ALTER VIEW V_EMPLOYEE COMPILE;
-- 删除视图
DROP VIEW [IF EXISTS] [模式名.]V_EMPLOYEE [CASCADE];
视图查询定义通常通过 CREATE OR REPLACE VIEW 修改;ALTER VIEW 主要用于编译、属性维护等操作。删除视图不会删除基表数据;使用 CASCADE 前应确认依赖对象会受到影响。
WITH CHECK OPTION / WITH READ ONLY
CREATE VIEW V_ACTIVE_EMP AS
SELECT EMP_ID, EMP_NAME, STATUS
FROM EMPLOYEE
WHERE STATUS = '1'
WITH CHECK OPTION;
CREATE VIEW V_EMP_READONLY AS
SELECT EMP_ID, EMP_NAME, SALARY
FROM EMPLOYEE
WITH READ ONLY;
WITH CHECK OPTION 要求通过视图执行 INSERT 或 UPDATE 后,数据仍满足视图的 WHERE 条件,防止更新后数据“跑出”视图;WITH READ ONLY 禁止通过该视图执行增删改。复杂连接、聚合、DISTINCT 等视图即使未显式指定只读,也可能天然不可更新。
CREATE SCHEMA:模式创建与授权
CREATE SCHEMA AUTHORIZATION APP_USER;
-- 在模式中创建对象并授权
CREATE SCHEMA AUTHORIZATION APP_USER
CREATE TABLE T_ORDER (
ORDER_ID INT PRIMARY KEY,
AMOUNT DECIMAL(12,2)
)
GRANT SELECT ON T_ORDER TO REPORT_USER;
模式通常与数据库用户关联,用于对象命名空间和权限隔离。实际环境中常先由 DBA 创建用户,再由对象所有者或 DBA 执行 GRANT;不要把模式名、用户名和表名混用。
CREATE SEQUENCE:序列参数
CREATE SEQUENCE SEQ_ORDER_ID
INCREMENT BY 1
START WITH 1000
MAXVALUE 999999999
NOCYCLE
CACHE 20;
SELECT SEQ_ORDER_ID.NEXTVAL FROM DUAL;
SELECT SEQ_ORDER_ID.CURRVAL FROM DUAL;
INCREMENT BY 指定步长;START WITH 指定初始值;MAXVALUE/MINVALUE 限定边界;CYCLE 到边界后循环,NOCYCLE 到边界时报错;CACHE n 预缓存序列值以减少争用,数据库异常中止可能造成间隔跳号。序列不保证连续,也不等同于无间隙业务编号。
CREATE SYNONYM:同义词
CREATE [OR REPLACE] SYNONYM S_EMPLOYEE
FOR HR.EMPLOYEE;
CREATE PUBLIC SYNONYM S_EMPLOYEE
FOR HR.EMPLOYEE;
私有同义词只对创建者(或被授权用户)可见;公共同义词对所有用户可见,但仍需具备目标对象权限。适合屏蔽模式名、兼容对象改名和简化跨模式访问;生产环境应谨慎使用公共同义词,避免命名冲突和权限边界不清。
COMMENT:注释规范
COMMENT ON TABLE EMPLOYEE IS '员工基本信息';
COMMENT ON COLUMN EMPLOYEE.EMP_ID IS '员工唯一编号';
COMMENT ON VIEW V_ACTIVE_EMP IS '在职员工查询视图';
注释对象名应写明模式名(跨模式时使用 模式.对象),文本使用单引号;再次执行会覆盖原注释,删除注释可使用 IS NULL(以当前 DM 版本支持情况为准)。
INSERT:单行、多行与查询插入
-- 单行插入:适合少量、参数化写入
INSERT INTO EMPLOYEE (EMP_ID, EMP_NAME, DEPT_ID)
VALUES (1001, '张三', 10);
-- 多行插入:一次语句写入多组常量
INSERT ALL
INTO EMPLOYEE (EMP_ID, EMP_NAME, DEPT_ID) VALUES (1002, '李四', 10)
INTO EMPLOYEE (EMP_ID, EMP_NAME, DEPT_ID) VALUES (1003, '王五', 20)
SELECT 1 FROM DUAL;
-- 从查询结果插入:适合装载、迁移和汇总结果
INSERT INTO EMPLOYEE_HIS (EMP_ID, EMP_NAME, DEPT_ID)
SELECT EMP_ID, EMP_NAME, DEPT_ID
FROM EMPLOYEE
WHERE STATUS = '0';
单行写法可读性和参数绑定最好;INSERT ALL 减少往返次数;INSERT ... SELECT 通常最适合批量装载,但应关注日志、锁、约束和目标表索引维护成本。
UPDATE:标准与关联更新
UPDATE EMPLOYEE
SET SALARY = SALARY * 1.05,
UPDATE_TIME = CURRENT_TIMESTAMP
WHERE DEPT_ID = 10;
-- DM 常用相关子查询写法(兼容性较好)
UPDATE EMPLOYEE E
SET E.DEPT_NAME = (SELECT D.DEPT_NAME FROM DEPARTMENT D WHERE D.DEPT_ID = E.DEPT_ID)
WHERE EXISTS (SELECT 1 FROM DEPARTMENT D WHERE D.DEPT_ID = E.DEPT_ID);
关联更新的连接键应保证一对一;若子查询返回多行会报错。更新前先用同一 WHERE 条件执行 SELECT 核对影响范围,并注意触发器、唯一约束和空值传播。若目标 DM 版本启用 UPDATE ... FROM 扩展,可写为:
UPDATE EMPLOYEE E
SET E.SALARY = E.SALARY * 1.05
FROM DEPARTMENT D
WHERE D.DEPT_ID = E.DEPT_ID
AND D.DEPT_LEVEL = 'A';
不同兼容模式对该扩展的支持可能不同;跨版本脚本优先使用前面的相关子查询写法并实测。
DELETE:标准与关联删除
DELETE FROM EMPLOYEE
WHERE STATUS = '0';
-- 关联删除的通用写法
DELETE FROM EMPLOYEE E
WHERE EXISTS (
SELECT 1 FROM DEPARTMENT D
WHERE D.DEPT_ID = E.DEPT_ID AND D.ENABLED = '0'
);
关联删除应使用 EXISTS 或主键集合限定目标行,避免连接产生重复匹配。若目标 DM 版本支持 DELETE ... FROM 扩展,可写为:
DELETE FROM EMPLOYEE E
USING DEPARTMENT D
WHERE D.DEPT_ID = E.DEPT_ID
AND D.ENABLED = '0';
执行前确认外键、级联规则和触发器;大批量删除可分批提交,并评估日志与锁。DELETE ... FROM/USING 不是所有 DM 版本都兼容,跨版本脚本应优先采用 EXISTS 写法并按目标版本验证。
MERGE:同步与加载
MERGE INTO EMPLOYEE T
USING EMPLOYEE_STAGE S
ON (T.EMP_ID = S.EMP_ID)
WHEN MATCHED THEN
UPDATE SET T.EMP_NAME = S.EMP_NAME,
T.SALARY = S.SALARY
WHEN NOT MATCHED THEN
INSERT (EMP_ID, EMP_NAME, SALARY)
VALUES (S.EMP_ID, S.EMP_NAME, S.SALARY);
结构可概括为:MERGE INTO 目标 USING 来源 ON 匹配条件 → WHEN MATCHED(更新/删除) → WHEN NOT MATCHED(插入)。WHEN MATCHED 处理已存在键,WHEN NOT MATCHED 处理新增键;来源键必须唯一,否则同一目标行可能被多次匹配。适用于增量同步、ETL 装载和维表合并,执行前应校验来源数据去重及唯一约束。
RETURNING 子句
INSERT INTO EMPLOYEE (EMP_ID, EMP_NAME)
VALUES (SEQ_EMP_ID.NEXTVAL, '赵六')
RETURNING EMP_ID INTO :new_emp_id;
UPDATE EMPLOYEE
SET SALARY = SALARY + 1000
WHERE EMP_ID = :emp_id
RETURNING EMP_ID, SALARY INTO :out_id, :out_salary;
RETURNING 在 DML 完成后直接返回受影响行的列值,适合获取自增/序列主键、更新后的金额或删除前的业务字段,可减少再次查询。批量返回、客户端绑定变量和驱动支持存在差异,应按使用的 DM 驱动验证。
SELECT 完整结构与执行顺序
SELECT [DISTINCT] 列或表达式
FROM 表或视图
[JOIN ... ON ...]
[WHERE 条件]
[GROUP BY 分组列]
[HAVING 分组条件]
[ORDER BY 排序列 [ASC|DESC] [NULLS FIRST|LAST]]
[LIMIT n [OFFSET m]];
逻辑执行顺序通常为:FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。窗口函数在 SELECT 阶段计算,不能直接写在 WHERE 中;需要先用子查询或公用表表达式筛选。
WHERE 子句
WHERE SALARY >= 5000 AND DEPT_ID IN (10, 20) AND HIRE_DATE BETWEEN DATE '2020-01-01' AND DATE '2024-12-31' AND EMP_NAME LIKE '张%' AND PHONE IS NULL
比较运算符:=、<>、!=、>、>=、<、<=;逻辑运算符:NOT、AND、OR,混用时用括号明确优先级。BETWEEN 两端包含边界;IN 遇到 NULL 时要结合三值逻辑;LIKE 中 % 匹配任意长度、_ 匹配单个字符;判断空值必须使用 IS NULL/IS NOT NULL,不能写 = NULL。
ORDER BY 与空值顺序
SELECT EMP_ID, SALARY, HIRE_DATE
FROM EMPLOYEE
ORDER BY DEPT_ID ASC, SALARY DESC NULLS LAST, EMP_ID;
可按多列排序,前列相同时再比较后列。为保证分页稳定,应追加唯一键;NULLS FIRST/LAST 显式控制空值位置,避免受数据库默认排序规则影响。
LIMIT / TOP / ROWNUM 分页
-- LIMIT:适合支持 LIMIT 的版本
SELECT * FROM EMPLOYEE ORDER BY EMP_ID LIMIT 20 OFFSET 40;
-- TOP:取前 N 行
SELECT TOP 20 * FROM EMPLOYEE ORDER BY EMP_ID;
-- ROWNUM:用嵌套查询实现区间分页
SELECT * FROM (
SELECT E.*, ROWNUM RN
FROM (SELECT * FROM EMPLOYEE ORDER BY EMP_ID) E
WHERE ROWNUM <= 60
)
WHERE RN > 40;
LIMIT 直观且适合现代分页;TOP 适合只取前几行;ROWNUM 兼容传统 Oracle 风格但必须先排序再截取。大偏移量分页会扫描并丢弃前面大量行,海量数据建议使用基于唯一键的“游标/键集分页”。
GROUP BY 与多维分组
SELECT DEPT_ID, STATUS, COUNT(*) AS CNT, SUM(SALARY) AS TOTAL
FROM EMPLOYEE
GROUP BY DEPT_ID, STATUS;
SELECT DEPT_ID, STATUS, SUM(SALARY)
FROM EMPLOYEE
GROUP BY ROLLUP (DEPT_ID, STATUS);
SELECT DEPT_ID, STATUS, SUM(SALARY)
FROM EMPLOYEE
GROUP BY CUBE (DEPT_ID, STATUS);
SELECT DEPT_ID, STATUS, SUM(SALARY)
FROM EMPLOYEE
GROUP BY GROUPING SETS ((DEPT_ID), (STATUS), ());
ROLLUP 生成从明细到逐级小计及总计;CUBE 生成所有维度组合;GROUPING SETS 精确指定需要的分组集合,避免不必要的组合。小计行中的 NULL 可结合 GROUPING() 区分真实空值与汇总空值。
聚合函数
| 函数 | 签名示例 | NULL 与 DISTINCT 注意 |
|---|---|---|
| COUNT | COUNT(*)、COUNT(expr)、COUNT(DISTINCT expr) |
COUNT(*) 统计行数;COUNT(expr) 忽略 NULL;DISTINCT 统计去重非空值。 |
| SUM | SUM([DISTINCT] expr) |
忽略 NULL;全为 NULL 时结果为 NULL。 |
| AVG | AVG([DISTINCT] expr) |
忽略 NULL,按非空值计算平均数。 |
| MAX/MIN | MAX(expr)、MIN(expr) |
忽略 NULL,可用于日期和字符比较。 |
| LISTAGG | LISTAGG(expr, ',') WITHIN GROUP (ORDER BY expr) |
忽略 NULL;需控制结果长度,排序决定拼接顺序。 |
| WM_CONCAT | WM_CONCAT(expr) |
达梦兼容函数,版本/兼容模式可能有差异;新开发优先使用 LISTAGG。 |
HAVING:分组后过滤
SELECT DEPT_ID, COUNT(*) AS CNT
FROM EMPLOYEE
WHERE STATUS = '1'
GROUP BY DEPT_ID
HAVING COUNT(*) >= 10;
WHERE 在分组前过滤明细行,通常更有利于减少参与聚合的数据量;HAVING 在分组后过滤聚合结果,适合 COUNT/SUM/AVG 等条件。能写在 WHERE 的条件不要放到 HAVING。
INNER JOIN 与隐式连接
SELECT E.EMP_ID, E.EMP_NAME, D.DEPT_NAME
FROM EMPLOYEE E
INNER JOIN DEPARTMENT D ON D.DEPT_ID = E.DEPT_ID;
-- 隐式连接(不推荐用于复杂 SQL)
SELECT E.EMP_ID, E.EMP_NAME, D.DEPT_NAME
FROM EMPLOYEE E, DEPARTMENT D
WHERE D.DEPT_ID = E.DEPT_ID;
两者在连接条件完整时结果等价;显式 JOIN ... ON 更清晰,也能避免遗漏条件导致笛卡尔积。
LEFT/RIGHT/FULL OUTER JOIN
左连接保留左表全部行,右连接保留右表全部行,全连接保留两侧全部行。连接条件应优先放在 ON 中;把右表过滤条件写入 WHERE 往往会把左连接退化为内连接。
SELECT E.EMP_ID, D.DEPT_NAME
FROM EMPLOYEE E
LEFT JOIN DEPARTMENT D
ON D.DEPT_ID = E.DEPT_ID
AND D.ENABLED = '1';
CROSS JOIN
SELECT S.SIZE_NAME, C.COLOR_NAME
FROM SIZES S
CROSS JOIN COLORS C;
交叉连接返回两表行数的乘积,适合生成商品规格组合、日历与维度展开;使用前应确认数据量,避免意外笛卡尔积。
自连接
SELECT E.EMP_NAME AS EMPLOYEE_NAME,
M.EMP_NAME AS MANAGER_NAME
FROM EMPLOYEE E
LEFT JOIN EMPLOYEE M ON M.EMP_ID = E.MANAGER_ID;
自连接通过同一表的不同别名表示上下级、配对或重复数据比对。树形查询的多层遍历应结合递归查询或层次查询语法,并防止循环引用。
SELECT EMP_ID FROM EMPLOYEE_2024
UNION
SELECT EMP_ID FROM EMPLOYEE_2025;
SELECT EMP_ID FROM EMPLOYEE_2024
UNION ALL
SELECT EMP_ID FROM EMPLOYEE_2025;
SELECT EMP_ID FROM EMPLOYEE_2024
INTERSECT
SELECT EMP_ID FROM EMPLOYEE_2025;
SELECT EMP_ID FROM EMPLOYEE_2024
MINUS
SELECT EMP_ID FROM EMPLOYEE_2025;
UNION 合并后去重,结果更小但需要排序或哈希,通常慢于 UNION ALL;确认来源集合互不重复时优先 UNION ALL。INTERSECT 返回两边交集;达梦常用 MINUS 求差集,部分兼容模式支持 EXCEPT,迁移时应按数据库模式验证。集合两侧列数、顺序和数据类型必须兼容,最终排序只能写在整个集合查询末尾。
文章
阅读量
获赞
