在学习 SQL 的过程中,你可能会发现:同样的 "建表语句" 在 MySQL 能运行,在 Oracle 却报错;"分页查询" 的写法在 SQL Server 和 MySQL 完全不同。这是因为 MySQL、Oracle、SQL Server 是三大主流关系型数据库,虽都支持标准 SQL,但在 "基础特性、语法细节、适用场景" 上存在明显差异。今天我们从学习和实操的角度,拆解三者的核心区别,帮你避免 "跨库踩坑"。
我整理了一些学习资料,包含课程、专业、考试等内容,还有游戏和软件的合集。
学习资料合集文档https://www.kdocs.cn/l/cjchDXwklk1B
一、三大数据库的基础特性差异
首先从 "定位、开源性、数据存储、默认配置" 等基础维度,快速建立对三者的整体认知,这是理解语法差异的前提。
|-----------|----------------------------------|-----------------------------|-------------------------------------------|
| 对比维度 | MySQL(8.0+) | Oracle(19c+) | SQL Server(2022+) |
| 开源性 | 开源免费(社区版),商业版收费 | 闭源,需付费授权 | 闭源,需付费授权(有免费开发版) |
| 定位与场景 | 轻量灵活,适合中小型项目、互联网场景(如电商网站、APP 后端) | 大型企业级应用(如银行、政务系统),支持高并发、高可用 | 微软生态项目(如.NET 开发的系统)、中小型企业应用 |
| 数据存储 | 以 "文件" 形式存储(如 InnoDB 引擎的.ibd 文件) | 以 "表空间" 为单位存储,支持分区表、大文件存储 | 以 "数据库文件(.mdf)+ 日志文件(.ldf)" 存储 |
| 默认端口 | 3306 | 1521 | 1433 |
| 默认字符集 | utf8mb4(支持 emoji 表情) | AL32UTF8(类似 UTF-8) | SQL_Latin1_General_CP1_CI_AS(需手动设置 UTF-8) |
| 事务支持 | 支持(InnoDB 引擎),默认自动提交 | 支持,默认自动提交,事务稳定性极强 | 支持,默认自动提交,与微软产品兼容性好 |
二、核心语法差异:初学者高频用到的 5 个场景
语法差异是学习中最易踩坑的地方,我们聚焦 "建表、数据类型、分页查询、函数、事务隔离级别" 这 5 个最常用的场景,对比具体写法。
场景 1:建表语句差异(自增、主键、默认值)
建表是 SQL 入门的基础操作,但三者在 "自增字段""默认值设置" 上写法不同,尤其是 Oracle 没有 "自增关键字",需要用序列(Sequence)实现。
例子:创建 "学生表(student)",含自增主键(student_id)
- MySQL 写法:用AUTO_INCREMENT关键字实现自增
sql
CREATE TABLE student (
student_id INT PRIMARY KEY AUTO_INCREMENT, -- 自增主键
student_name VARCHAR(20) NOT NULL,
age INT DEFAULT 18, -- 默认值18
enroll_date DATE -- 日期类型
);
- Oracle 写法:无AUTO_INCREMENT,需先建序列,再通过触发器或直接调用序列赋值
sql
-- 1. 先创建序列(生成自增ID)
CREATE SEQUENCE seq_student_id
START WITH 1 -- 从1开始
INCREMENT BY 1 -- 每次增1
NOCYCLE; -- 不循环(到最大值后停止)
-- 2. 创建学生表
CREATE TABLE student (
student_id INT PRIMARY KEY, -- 需通过序列赋值
student_name VARCHAR2(20) NOT NULL, -- 注意:Oracle用VARCHAR2,不是VARCHAR
age INT DEFAULT 18,
enroll_date DATE
);
-- 3. 插入数据时调用序列(或建触发器自动赋值)
INSERT INTO student (student_id, student_name)
VALUES (seq_student_id.NEXTVAL, '张三'); -- NEXTVAL获取序列下一个值
- SQL Server 写法:用IDENTITY(起始值, 增量)实现自增
sql
CREATE TABLE student (
student_id INT PRIMARY KEY IDENTITY(1,1), -- 自增:从1开始,每次增1
student_name VARCHAR(20) NOT NULL,
age INT DEFAULT 18,
enroll_date DATE
);
-- 插入数据时无需指定自增字段
INSERT INTO student (student_name) VALUES ('张三');
场景 2:常用数据类型差异
虽然三者都支持 "数值、字符串、日期" 类型,但部分类型的名称和取值范围不同,比如 Oracle 的字符串类型是VARCHAR2,SQL Server 的长文本类型是TEXT。
|--------|----------------------------------|---------------------------------------------------|-------------------------------|
| 数据类型分类 | MySQL | Oracle | SQL Server |
| 字符串 | VARCHAR (n)、TEXT(长文本) | VARCHAR2 (n)、CLOB(大文本) | VARCHAR (n)、TEXT(长文本) |
| 整数 | INT、BIGINT | INT、NUMBER(10) | INT、BIGINT |
| 小数 | DECIMAL(p,s)、FLOAT | NUMBER(p,s) | DECIMAL(p,s)、FLOAT |
| 日期 | DATE(日期)、DATETIME(日期时间) | DATE(日期)、TIMESTAMP(日期时间) | DATE(日期时间)、DATETIME2(高精度日期时间) |
| 布尔值 | BOOLEAN(本质是 TINYINT,1 = 真,0 = 假) | 无 BOOLEAN,用 NUMBER (1) 或 CHAR (1) 模拟(1 = 真,0 = 假) | BIT(1 = 真,0 = 假) |
场景 3:分页查询差异(最易混淆)
当数据量较大时,需要分页查询(如 "查询第 2 页,每页 10 条数据"),三者的写法完全不同:MySQL 用LIMIT,Oracle 用ROWNUM,SQL Server 用OFFSET...FETCH NEXT。
需求:查询学生表中,按 student_id 升序,取第 2 页(11-20 条数据,每页 10 条)
- MySQL 写法:LIMIT 偏移量, 每页条数(偏移量 =(页数 - 1)× 每页条数)
sql
SELECT * FROM student
ORDER BY student_id ASC
LIMIT 10, 10; -- 偏移量10(跳过前10条),取10条(11-20条)
- Oracle 写法:用ROWNUM(伪列,代表行号),需嵌套子查询
sql
-- 先排序并加行号,再筛选行号范围(11-20)
SELECT * FROM (
SELECT s.*, ROWNUM rn -- 给结果加行号rn
FROM (SELECT * FROM student ORDER BY student_id ASC) s
)
WHERE rn BETWEEN 11 AND 20; -- 筛选行号11-20
- SQL Server 写法:OFFSET 偏移量 ROWS FETCH NEXT 每页条数 ROWS ONLY
sql
SELECT * FROM student
ORDER BY student_id ASC
OFFSET 10 ROWS -- 跳过前10条
FETCH NEXT 10 ROWS ONLY; -- 取接下来10条(11-20条)
场景 4:常用函数差异(日期、字符串、聚合)
函数是 SQL 查询的核心工具,三者在 "日期函数""字符串函数" 上差异最明显,比如 "获取当前日期" 的函数完全不同。
|-------|----------------------|----------------------------|--------------------------------|-------------------|
| 函数类型 | 需求描述 | MySQL | Oracle | SQL Server |
| 日期函数 | 获取当前日期时间 | NOW() | SYSDATE | GETDATE() |
| | 提取日期中的年份 | YEAR(enroll_date) | EXTRACT(YEAR FROM enroll_date) | YEAR(enroll_date) |
| 字符串函数 | 拼接字符串(如 "张三 - 2025") | CONCAT (' 张三 ', '-', 2025) | ' 张三' | |
| | 取字符串长度 | LENGTH(student_name) | LENGTH(student_name) | LEN(student_name) |
| 聚合函数 | 统计非 NULL 值数量 | COUNT(student_id) | COUNT(student_id) | COUNT(student_id) |
场景 5:事务隔离级别差异
事务隔离级别决定了并发访问时数据的一致性,三者支持的隔离级别基本一致,但默认隔离级别不同,可能导致相同代码在不同数据库中出现不同结果(如脏读、不可重复读)。
|------------|-----------------------|--------------------------------------------------------------------|
| 数据库 | 默认隔离级别 | 支持的隔离级别(按一致性从低到高) |
| MySQL | REPEATABLE READ(可重复读) | READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE |
| Oracle | READ COMMITTED(读已提交) | READ COMMITTED → SERIALIZABLE(不支持前两个低级别) |
| SQL Server | READ COMMITTED(读已提交) | READ UNCOMMITTED → READ COMMITTED → REPEATABLE READ → SERIALIZABLE |
说明:MySQL 的默认隔离级别(REPEATABLE READ)能避免 "不可重复读",而 Oracle 和 SQL Server 的默认级别(READ COMMITTED)允许 "不可重复读",但能避免 "脏读",这在并发场景中需要特别注意。
三、适用场景与学习建议
了解差异后,更重要的是知道 "什么时候用哪个数据库",以及 "大学生该如何学习"。
1. 适用场景选择
- 选 MySQL:如果做个人项目、互联网方向实习(如电商、短视频后端),或学习轻量级数据库,优先学 MySQL------ 开源免费,资源多,上手快,是企业中使用最广泛的数据库之一。
- 选 Oracle:如果未来想进银行、国企、大型企业做后端开发,需要学 Oracle------ 它适合处理海量数据和高并发,稳定性极强,但学习成本较高,语法较复杂。
- 选 SQL Server:如果学.NET 开发,或在微软生态的公司实习(如用 C# 做系统),需要学 SQL Server------ 与 Visual Studio、.NET 框架兼容性好,操作界面友好,但跨平台能力弱(主要支持 Windows)。
2. 初学者学习建议
- 先精通一个,再触类旁通:建议先把 MySQL 学透(开源免费,资料多),掌握标准 SQL 语法后,再对比学习 Oracle 或 SQL Server 的差异点 ------ 比如学会 MySQL 的LIMIT后,再记 Oracle 的ROWNUM和 SQL Server 的OFFSET,避免同时学多个导致混淆。
- 重点关注 "标准 SQL":大部分查询语句(如SELECT、JOIN、GROUP BY)是标准 SQL,在三个数据库中通用,优先掌握这些通用语法,再针对性学习差异语法。
- 多实操验证差异:比如把 MySQL 的建表语句改成 Oracle 写法,运行后观察报错,再根据报错调整(如把VARCHAR改成VARCHAR2,添加序列),通过实操加深记忆。
四、总结:核心差异速查表
为方便快速查阅,整理三者最核心的差异点:
|--------|-----------------|-------------------|---------------------|
| 差异类型 | MySQL | Oracle | SQL Server |
| 自增实现 | AUTO_INCREMENT | 序列(Sequence)+ 触发器 | IDENTITY(1,1) |
| 分页查询 | LIMIT 偏移量,条数 | ROWNUM(嵌套子查询) | OFFSET...FETCH NEXT |
| 字符串类型 | VARCHAR、TEXT | VARCHAR2、CLOB | VARCHAR、TEXT |
| 当前日期函数 | NOW() | SYSDATE | GETDATE() |
| 默认隔离级别 | REPEATABLE READ | READ COMMITTED | READ COMMITTED |
掌握这些差异,能帮你在学习和工作中快速适应不同数据库环境,避免 "语法报错" 和 "逻辑异常",更高效地使用 SQL 处理数据。