前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • HTTP

  • 浏览器相关

  • 计算机基础

    • Linux
    • Network
    • OS
    • SQL
    • MySQL
    • Redis
    • Socket
    • 攻击技术
    • 缓存
    • 集群

# 一、基础

30 秒速记

  • 模式(schema)= 数据的结构契约:有哪些表、每列什么类型、能不能为空、有哪些约束
  • 主键唯一标识一行,不改、不复用:被外键和日志引用着,改了或复用了就会指错对象
  • 主键尽量用无业务含义的自增 ID 或 UUID,手机号、邮箱这种会变的放唯一索引
  • SQL 有 ANSI 标准,各家有方言:Oracle 的 PL/SQL、SQL Server 的 T-SQL;USE db 和 # 注释在 PostgreSQL 里都不认
  • 关键字不区分大小写;表名看系统和配置(MySQL 在 Linux 上默认区分),字符串比较看排序规则(utf8mb4_0900_ai_ci 不区分)

这一节的核心是三件事:模式是数据的结构契约,主键是一行数据的身份证,SQL 有标准但各家数据库都有自己的方言。 主键一旦用了就别改也别复用,因为外键、日志、缓存、外部链接都拿它指向这一行,改了或者被新数据复用就全指错了,所以我一般用无业务含义的自增 ID 当主键。方言这块最容易翻车:# 注释和 USE test 是 MySQL 的写法,换到 PostgreSQL 就报错。大小写也一样,关键字随便写,表名和字符串值区不区分大小写,要看数据库、操作系统和排序规则。

模式定义了数据如何存储、存储什么样的数据以及数据如何分解等信息,数据库和表都有模式。

主键的值不允许修改,也不允许复用(不能将已经删除的主键值赋给新数据行的主键)。

SQL(Structured Query Language),标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL。各个 DBMS 都有自己的实现,如 PL/SQL、Transact-SQL 等。

SQL 语句不区分大小写,但是数据库表名、列名和值是否区分依赖于具体的 DBMS 以及配置。

SQL 支持以下三种注释:

# 注释
SELECT *
FROM mytable; -- 注释
/* 注释1
   注释2 */
@前端进阶之旅: 代码已经复制到剪贴板

数据库创建与使用:

CREATE DATABASE test;
USE test;
@前端进阶之旅: 代码已经复制到剪贴板

原理拆解: 模式可以理解为数据库对象的结构契约:列的数据类型、是否允许 NULL、唯一性、对象之间的关联等信息共同决定什么数据能够进入系统。主键负责唯一标识一行,通常还会被其他表的外键引用;若修改已经被引用的主键,会扩大更新范围并破坏标识的稳定性。因此业务设计常使用无业务含义的代理键作为主键,把手机号、订单编号等可能变化的值放在普通唯一列中。题目约定删除后的主键也不复用,这有利于避免旧日志、缓存或外部链接错误指向新记录。

具体辨析: SQL 标准定义通用语法和语义,DBMS 再提供自己的数据类型、函数、过程语言及管理命令。PL/SQL 主要属于 Oracle 体系,Transact-SQL 属于 SQL Server 体系;能够在某一产品执行的语句,不代表能原样迁移到另一产品。USE test、# 注释也不是所有数据库都接受,因此迁移脚本不能只凭“属于 SQL”判断兼容性。

边界与排查: 关键字不区分大小写不等于所有标识符和字符串都不区分大小写。字符串比较通常受排序规则影响,标识符行为还可能受操作系统、引号方式及数据库配置影响。验证兼容性时,应在目标 DBMS 建立最小数据库和表,分别测试建库、切库、注释、大小写比较及约束错误,并通过产品文档确认方言边界,而不是依赖另一套数据库中的执行结果。

面试官追问

追问 1SELECT 大小写随便写,那表名、字符串值是不是也不区分?
参考回答

不一定。MySQL 表名在 Linux 上默认区分大小写,在 Windows 和 macOS 上不区分,由 lower_case_table_names 控制;字符串比较看排序规则,_ci 结尾的不区分,_bin 和 _cs 区分。本地 macOS 跑得好好的,部署到 Linux 报表不存在,就是这个原因。

追问 2一个初始化脚本要同时在 MySQL 和 PostgreSQL 上跑,注释怎么写?
参考回答

只用 -- 和 /* */,别用 #,它只有 MySQL 认。还要注意 MySQL 的 -- 后面必须跟一个空格,--注释 会报语法错误。

追问 3删掉的订单留下空号,开发想把编号补给新订单保持连续,行吗?
参考回答

不行。旧订单的日志、退款记录、外部系统可能还拿着这个 ID,复用后就指到新订单上了。如果业务就是要连续的展示编号,单独加一列订单号,主键别动。

追问 4手机号直接当用户表主键,有什么问题?
参考回答

手机号会换,主键一改,所有引用它的外键表都得跟着改。而且字符串主键比整数占空间,在 InnoDB 里每个二级索引都会带上主键值。用自增 id 做主键,手机号加唯一索引。

追问 5脚本迁到 PostgreSQL 后卡在 USE test 这一行,怎么改?
参考回答

PostgreSQL 没有 USE,切库是在连接时指定的,psql 里用 \c test,程序里改连接串的数据库名。同一个库内要分组用 schema,配合 SET search_path。

# 二、创建表

30 秒速记

  • CREATE TABLE 一次声明:列名 + 类型 + 是否可空 + 默认值 + 主键
  • id INT NOT NULL AUTO_INCREMENT + PRIMARY KEY (id):自增主键,插入时不传 id 自动生成
  • col1 INT NOT NULL DEFAULT 1:不传就是 1,显式传 NULL 会报错,默认值不兜底 NULL
  • VARCHAR(45) 在 MySQL 5 以后是 45 个字符,不是字节;DATE 只存日期不存时间
  • 自增写法是方言:MySQL 的 AUTO_INCREMENT、PostgreSQL 的 GENERATED ALWAYS AS IDENTITY(老写法 SERIAL)、SQL Server 的 IDENTITY(1,1)

建表就是把每一列的类型、能不能为空、默认值和主键一次说清楚,数据库以后就按这份约定把关。 这个例子里 id 是自增主键,插入时不用管它;col1 不能为空、默认值 1;col2 是最长 45 个字符的可空字符串;col3 是可空日期。最容易误会的是默认值:不写这一列才会用默认值,显式写 NULL 是另一回事,碰上 NOT NULL 直接报错。另外 AUTO_INCREMENT、反引号、# 注释都是 MySQL 方言,换库要改。

CREATE TABLE mytable (
  # int 类型,不为空,自增
  id INT NOT NULL AUTO_INCREMENT,
  # int 类型,不可为空,默认值为 1,不为空
  col1 INT NOT NULL DEFAULT 1,
  # 变长字符串类型,最长为 45 个字符,可以为空
  col2 VARCHAR(45) NULL,
  # 日期类型,可为空
  col3 DATE NULL,
  # 设置主键为 id
  PRIMARY KEY (`id`));
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1一个接口不传 col1,另一个传了 NULL,两条记录都会是 1 吗?
参考回答

不会。不传才用默认值 1;显式传 NULL 碰上 NOT NULL,MySQL 单行插入会直接报 Column 'col1' cannot be null。想显式用默认值,写 VALUES (DEFAULT)。

追问 2VARCHAR(45) 存 45 个汉字会被截断吗?
参考回答

MySQL 5 以后长度按字符算,45 个汉字能存下,用 utf8mb4 时占用的字节最多到 180。超过 45 个字符,严格模式下报错,非严格模式会静默截断并给一条警告,所以线上一定要开严格模式。

追问 3这段建表脚本放到 PostgreSQL 里跑报错,要改哪些地方?
参考回答

三处:# 注释改成 --;反引号改成双引号或者干脆去掉;AUTO_INCREMENT 改成 id INT GENERATED ALWAYS AS IDENTITY(或者老写法 SERIAL)。

追问 4id 写了 AUTO_INCREMENT 却忘了 PRIMARY KEY,会怎样?
参考回答

MySQL 直接拒绝建表,它要求自增列必须是某个索引的第一列。真正要防的是另一种情况:主键定义在脚本最后一行,前面某处语法错导致整句失败,所以建完表要 SHOW CREATE TABLE 核对一下。

追问 5想把已有表的 col2 改成必填,直接加 NOT NULL 可以吗?
参考回答

先查 SELECT COUNT(*) FROM mytable WHERE col2 IS NULL。有空值的话,严格模式下 ALTER 会失败,得先把空值更新成一个合理的值,同时改上游的输入校验,再加约束。

# 三、修改表

30 秒速记

  • 加列:ALTER TABLE mytable ADD col CHAR(20); 列名和类型必写,约束和默认值按需加
  • 删列:ALTER TABLE mytable DROP COLUMN col; 删表:DROP TABLE mytable; 范围差一个数量级
  • DROP 删的是结构连同数据,MySQL 里 DDL 会隐式提交,没法 ROLLBACK;PostgreSQL 的 DDL 可以放进事务回滚
  • 重新 ADD 回来只恢复了空列,数据只能靠备份或 binlog 找回
  • 大表改结构会锁表:MySQL 8.0 加列多数能 ALGORITHM=INSTANT 秒完成,复杂变更用 gh-ost / pt-online-schema-change
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • HTTP

  • 浏览器相关

  • 计算机基础

    • Linux
    • Network
    • OS
    • SQL
      • 一、基础
      • 二、创建表
      • 三、修改表
      • 四、插入
      • 五、更新
      • 六、删除
      • 七、查询
        • DISTINCT
        • LIMIT
      • 八、排序
      • 九、过滤
      • 十、通配符
      • 十一、计算字段
      • 十二、函数
      • 十三、分组
      • 十四、子查询
      • 十五、连接
      • 十六、组合查询
      • 十七、视图
      • 十八、存储过程
      • 十九、游标
      • 二十、触发器
      • 二十一、事务管理
      • 二十二、字符集
      • 二十三、权限管理
    • MySQL
    • Redis
    • Socket
    • 攻击技术
    • 缓存
    • 集群
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

SQL|计算机基础篇

# 一、基础

30 秒速记

  • 模式(schema)= 数据的结构契约:有哪些表、每列什么类型、能不能为空、有哪些约束
  • 主键唯一标识一行,不改、不复用:被外键和日志引用着,改了或复用了就会指错对象
  • 主键尽量用无业务含义的自增 ID 或 UUID,手机号、邮箱这种会变的放唯一索引
  • SQL 有 ANSI 标准,各家有方言:Oracle 的 PL/SQL、SQL Server 的 T-SQL;USE db 和 # 注释在 PostgreSQL 里都不认
  • 关键字不区分大小写;表名看系统和配置(MySQL 在 Linux 上默认区分),字符串比较看排序规则(utf8mb4_0900_ai_ci 不区分)

这一节的核心是三件事:模式是数据的结构契约,主键是一行数据的身份证,SQL 有标准但各家数据库都有自己的方言。 主键一旦用了就别改也别复用,因为外键、日志、缓存、外部链接都拿它指向这一行,改了或者被新数据复用就全指错了,所以我一般用无业务含义的自增 ID 当主键。方言这块最容易翻车:# 注释和 USE test 是 MySQL 的写法,换到 PostgreSQL 就报错。大小写也一样,关键字随便写,表名和字符串值区不区分大小写,要看数据库、操作系统和排序规则。

模式定义了数据如何存储、存储什么样的数据以及数据如何分解等信息,数据库和表都有模式。

主键的值不允许修改,也不允许复用(不能将已经删除的主键值赋给新数据行的主键)。

SQL(Structured Query Language),标准 SQL 由 ANSI 标准委员会管理,从而称为 ANSI SQL。各个 DBMS 都有自己的实现,如 PL/SQL、Transact-SQL 等。

SQL 语句不区分大小写,但是数据库表名、列名和值是否区分依赖于具体的 DBMS 以及配置。

SQL 支持以下三种注释:

# 注释
SELECT *
FROM mytable; -- 注释
/* 注释1
   注释2 */
@前端进阶之旅: 代码已经复制到剪贴板

数据库创建与使用:

CREATE DATABASE test;
USE test;
@前端进阶之旅: 代码已经复制到剪贴板

原理拆解: 模式可以理解为数据库对象的结构契约:列的数据类型、是否允许 NULL、唯一性、对象之间的关联等信息共同决定什么数据能够进入系统。主键负责唯一标识一行,通常还会被其他表的外键引用;若修改已经被引用的主键,会扩大更新范围并破坏标识的稳定性。因此业务设计常使用无业务含义的代理键作为主键,把手机号、订单编号等可能变化的值放在普通唯一列中。题目约定删除后的主键也不复用,这有利于避免旧日志、缓存或外部链接错误指向新记录。

具体辨析: SQL 标准定义通用语法和语义,DBMS 再提供自己的数据类型、函数、过程语言及管理命令。PL/SQL 主要属于 Oracle 体系,Transact-SQL 属于 SQL Server 体系;能够在某一产品执行的语句,不代表能原样迁移到另一产品。USE test、# 注释也不是所有数据库都接受,因此迁移脚本不能只凭“属于 SQL”判断兼容性。

边界与排查: 关键字不区分大小写不等于所有标识符和字符串都不区分大小写。字符串比较通常受排序规则影响,标识符行为还可能受操作系统、引号方式及数据库配置影响。验证兼容性时,应在目标 DBMS 建立最小数据库和表,分别测试建库、切库、注释、大小写比较及约束错误,并通过产品文档确认方言边界,而不是依赖另一套数据库中的执行结果。

面试官追问

追问 1SELECT 大小写随便写,那表名、字符串值是不是也不区分?
参考回答

不一定。MySQL 表名在 Linux 上默认区分大小写,在 Windows 和 macOS 上不区分,由 lower_case_table_names 控制;字符串比较看排序规则,_ci 结尾的不区分,_bin 和 _cs 区分。本地 macOS 跑得好好的,部署到 Linux 报表不存在,就是这个原因。

追问 2一个初始化脚本要同时在 MySQL 和 PostgreSQL 上跑,注释怎么写?
参考回答

只用 -- 和 /* */,别用 #,它只有 MySQL 认。还要注意 MySQL 的 -- 后面必须跟一个空格,--注释 会报语法错误。

追问 3删掉的订单留下空号,开发想把编号补给新订单保持连续,行吗?
参考回答

不行。旧订单的日志、退款记录、外部系统可能还拿着这个 ID,复用后就指到新订单上了。如果业务就是要连续的展示编号,单独加一列订单号,主键别动。

追问 4手机号直接当用户表主键,有什么问题?
参考回答

手机号会换,主键一改,所有引用它的外键表都得跟着改。而且字符串主键比整数占空间,在 InnoDB 里每个二级索引都会带上主键值。用自增 id 做主键,手机号加唯一索引。

追问 5脚本迁到 PostgreSQL 后卡在 USE test 这一行,怎么改?
参考回答

PostgreSQL 没有 USE,切库是在连接时指定的,psql 里用 \c test,程序里改连接串的数据库名。同一个库内要分组用 schema,配合 SET search_path。

# 二、创建表

30 秒速记

  • CREATE TABLE 一次声明:列名 + 类型 + 是否可空 + 默认值 + 主键
  • id INT NOT NULL AUTO_INCREMENT + PRIMARY KEY (id):自增主键,插入时不传 id 自动生成
  • col1 INT NOT NULL DEFAULT 1:不传就是 1,显式传 NULL 会报错,默认值不兜底 NULL
  • VARCHAR(45) 在 MySQL 5 以后是 45 个字符,不是字节;DATE 只存日期不存时间
  • 自增写法是方言:MySQL 的 AUTO_INCREMENT、PostgreSQL 的 GENERATED ALWAYS AS IDENTITY(老写法 SERIAL)、SQL Server 的 IDENTITY(1,1)

建表就是把每一列的类型、能不能为空、默认值和主键一次说清楚,数据库以后就按这份约定把关。 这个例子里 id 是自增主键,插入时不用管它;col1 不能为空、默认值 1;col2 是最长 45 个字符的可空字符串;col3 是可空日期。最容易误会的是默认值:不写这一列才会用默认值,显式写 NULL 是另一回事,碰上 NOT NULL 直接报错。另外 AUTO_INCREMENT、反引号、# 注释都是 MySQL 方言,换库要改。

CREATE TABLE mytable (
  # int 类型,不为空,自增
  id INT NOT NULL AUTO_INCREMENT,
  # int 类型,不可为空,默认值为 1,不为空
  col1 INT NOT NULL DEFAULT 1,
  # 变长字符串类型,最长为 45 个字符,可以为空
  col2 VARCHAR(45) NULL,
  # 日期类型,可为空
  col3 DATE NULL,
  # 设置主键为 id
  PRIMARY KEY (`id`));
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1一个接口不传 col1,另一个传了 NULL,两条记录都会是 1 吗?
参考回答

不会。不传才用默认值 1;显式传 NULL 碰上 NOT NULL,MySQL 单行插入会直接报 Column 'col1' cannot be null。想显式用默认值,写 VALUES (DEFAULT)。

追问 2VARCHAR(45) 存 45 个汉字会被截断吗?
参考回答

MySQL 5 以后长度按字符算,45 个汉字能存下,用 utf8mb4 时占用的字节最多到 180。超过 45 个字符,严格模式下报错,非严格模式会静默截断并给一条警告,所以线上一定要开严格模式。

追问 3这段建表脚本放到 PostgreSQL 里跑报错,要改哪些地方?
参考回答

三处:# 注释改成 --;反引号改成双引号或者干脆去掉;AUTO_INCREMENT 改成 id INT GENERATED ALWAYS AS IDENTITY(或者老写法 SERIAL)。

追问 4id 写了 AUTO_INCREMENT 却忘了 PRIMARY KEY,会怎样?
参考回答

MySQL 直接拒绝建表,它要求自增列必须是某个索引的第一列。真正要防的是另一种情况:主键定义在脚本最后一行,前面某处语法错导致整句失败,所以建完表要 SHOW CREATE TABLE 核对一下。

追问 5想把已有表的 col2 改成必填,直接加 NOT NULL 可以吗?
参考回答

先查 SELECT COUNT(*) FROM mytable WHERE col2 IS NULL。有空值的话,严格模式下 ALTER 会失败,得先把空值更新成一个合理的值,同时改上游的输入校验,再加约束。

# 三、修改表

30 秒速记

  • 加列:ALTER TABLE mytable ADD col CHAR(20); 列名和类型必写,约束和默认值按需加
  • 删列:ALTER TABLE mytable DROP COLUMN col; 删表:DROP TABLE mytable; 范围差一个数量级
  • DROP 删的是结构连同数据,MySQL 里 DDL 会隐式提交,没法 ROLLBACK;PostgreSQL 的 DDL 可以放进事务回滚
  • 重新 ADD 回来只恢复了空列,数据只能靠备份或 binlog 找回
  • 大表改结构会锁表:MySQL 8.0 加列多数能 ALGORITHM=INSTANT 秒完成,复杂变更用 gh-ost / pt-online-schema-change

改表结构用 ALTER TABLE,ADD 加列,DROP COLUMN 删列,删整张表是 DROP TABLE,这三条看着简单,但都是不可逆的结构变更。 加列要写清列名和类型,比如 CHAR(20) 是固定长度 20 的字符串,存短了会补空格。删列删表最危险,在 MySQL 里 DDL 会自动提交,事务包着也回滚不了,误删了只能从备份恢复。我上线前一定先在预发跑一遍,确认表名列名,大表还要评估锁表时间,MySQL 8.0 加列一般能秒级完成,但改类型这类还是会重建表。

添加列

ALTER TABLE mytable
ADD col CHAR(20);
@前端进阶之旅: 代码已经复制到剪贴板

删除列

ALTER TABLE mytable
DROP COLUMN col;
@前端进阶之旅: 代码已经复制到剪贴板

删除表

DROP TABLE mytable;
@前端进阶之旅: 代码已经复制到剪贴板

← OSMySQL →

fe