当前位置: 首页 > news >正文

MySQL基础-从建库建表到增删改查

MySQL 基础:从建库建表到增删改查

刚开始学 MySQL 时,我最容易混淆的不是某一条语法,而是这些语句到底在解决什么问题。CREATEINSERTSELECT看起来都在“操作数据库”,但它们其实处在完全不同的阶段。

后来我把常用 SQL 按下面这条线重新整理了一遍:

  1. 先建数据库、建表,确定数据以什么结构保存;
  2. 再插入、修改、删除数据;
  3. 最后按条件查询、排序、分页和统计。

这篇文章用一个简单的用户表贯穿示例。环境按 MySQL 8.0 编写,代码可以直接复制到客户端执行。

一、先分清 DDL、DML 和 DQL

分类用途常见关键字
DDL定义数据库和表的结构CREATEALTERDROPTRUNCATE
DML写入和修改表中的数据INSERTUPDATEDELETE
DQL查询数据SELECT

可以把数据库想成一个仓库:

  • DDL 决定仓库有几个房间、每个货架放什么;
  • DML 负责把货物搬进来、换位置或清出去;
  • DQL 负责按条件找到需要的货物。

这个区分看似基础,后面排查 SQL 问题时却很有用。比如删错一列应该找ALTER TABLE,删错一行才是DELETE

二、准备一个练习数据库

1. 创建并进入数据库

createdatabaseifnotexistsmysql_practicedefaultcharactersetutf8mb4collateutf8mb4_0900_ai_ci;usemysql_practice;

utf8mb4可以完整保存中文和 emoji,实际项目里一般比旧的utf8更稳妥。

常用的数据库查看命令:

showdatabases;selectdatabase();showcreatedatabasemysql_practice;

2. 创建用户表

createtableusers(idbigintunsignedprimarykeyauto_increment,usernamevarchar(30)notnull,phonechar(11),birthdaydate,statustinyintnotnulldefault1,balancedecimal(10,2)notnulldefault0.00,created_atdatetimenotnulldefaultcurrent_timestamp,uniquekeyuk_users_username(username),uniquekeyuk_users_phone(phone))engine=InnoDBdefaultcharset=utf8mb4;

这里顺便解释几个常用类型:

类型适用场景
bigint主键、数量较大的整数
varchar(n)长度不固定的字符串,例如用户名
char(n)长度基本固定的字符串,例如手机号、状态码
decimal(m, d)金额等需要精确计算的小数
date只保存日期
datetime保存日期和时间

金额不建议用floatdouble。浮点数适合科学计算,但会有精度误差;订单金额、余额一类字段通常使用decimal

查看表是否创建成功:

showtables;descusers;showcreatetableusers;

三、DDL:修改表结构

需求变化后,经常要给已有表加字段或调整字段定义,这时用ALTER TABLE

1. 添加字段

altertableusersaddcolumnemailvarchar(100)afterphone;

2. 修改字段类型

altertableusersmodifycolumnusernamevarchar(50)notnull;

3. 修改字段名和类型

altertableusers changecolumnstatusaccount_statustinyintnotnulldefault1;

MySQL 8.0 还可以只重命名字段:

altertableusersrenamecolumnaccount_statustostatus;

4. 删除字段

altertableusersdropcolumnemail;

这类操作会改变表结构。生产环境执行前,除了备份,还要确认应用代码、接口和报表是否仍在使用该字段。

5.DELETETRUNCATEDROP的区别

写法实际效果
delete from users;删除全部行,保留表结构
truncate table users;快速清空表,通常会重置自增计数
drop table users;连表结构一起删除

它们都很危险,但危险的层级不同。DROP TABLE之后,字段、索引和数据都会消失。

四、DML:新增、修改和删除数据

1. INSERT:插入数据

日常开发更推荐指定字段名:

insertintousers(username,phone,birthday,balance)values('张三','13800000001','2001-02-03',100.00);

这样即使表后来增加了字段,原来的 SQL 也不容易受到影响。

一次插入多行:

insertintousers(username,phone,birthday,balance)values('李四','13800000002','2000-06-18',55.50),('王五',null,'1999-11-20',320.00),('赵六','13800000004',null,0.00);

需要复制查询结果时,可以使用INSERT ... SELECT

insertintovip_users(user_id,username)selectid,usernamefromuserswherebalance>=300;

目标字段数量、顺序和类型要与查询结果对应。

2. UPDATE:修改数据

updateuserssetphone='13900000001',balance=balance+50whereid=1;

我现在执行UPDATE前都会先跑一遍相同条件的查询:

selectid,username,phone,balancefromuserswhereid=1;

确认命中的确实是目标记录,再执行更新。这个习惯比背多少条语法都实用。

下面这条 SQL 没有WHERE,会修改整张表:

updateuserssetstatus=0;

如果需求真的是全表更新,最好也先统计行数,并在事务或备份可用的情况下操作。

3. DELETE:删除数据

deletefromuserswhereid=4;

同样先用SELECT检查范围:

select*fromuserswhereid=4;

删除手机号为空的用户:

deletefromuserswherephoneisnull;

NULL代表未知或不存在,不能写成phone = null,必须使用IS NULLIS NOT NULL

另外,DELETE删除的是整行,不是某个字段。如果只是清空手机号,应写:

updateuserssetphone=nullwhereid=1;

NULL和空字符串''也不是一回事:前者表示没有值,后者是一个长度为 0 的字符串。

五、DQL:把数据查出来

一条完整查询通常按下面的顺序书写:

select字段列表from表名where行过滤条件groupby分组字段having分组后的过滤条件orderby排序字段limit起始位置,返回行数;

逻辑执行顺序可以先记成:

FROM → WHERE → GROUP BY → 聚合 → HAVING → SELECT → ORDER BY → LIMIT

这能解释两个常见问题:

  • WHERE阶段还没完成分组,所以不能直接使用聚合函数;
  • HAVING在聚合之后执行,因此可以写HAVING AVG(score) >= 80

1. 查询需要的字段

selectid,username,phonefromusers;

练习时用SELECT *很方便,但业务代码最好明确列名。这样能减少无用数据传输,也不会因为表结构变化而突然多返回敏感字段。

字段可以使用别名和表达式:

selectusernameas用户名,balanceas余额,year(curdate())-year(birthday)as大致年龄fromusers;

去重查询:

selectdistinctstatusfromusers;

如果DISTINCT后面有多列,MySQL 判断的是这一组列的组合是否重复。

2. WHERE 条件查询

常用条件可以分成四类:

类型示例
比较balance >= 100status <> 0
范围birthday between '2000-01-01' and '2005-12-31'
集合status in (1, 2)
模糊匹配username like '张%'

组合多个条件:

selectid,username,balancefromuserswherestatus=1andbalance>=100;

AND的优先级高于OR。条件一复杂,建议主动加括号:

select*fromuserswherestatus=1and(balance>=300orbirthdayisnull);

LIKE有两个常用通配符:

  • %:匹配任意长度的字符,包括 0 个字符;
  • _:只匹配一个字符。
-- 姓张select*fromuserswhereusernamelike'张%';-- 名字正好两个字符select*fromuserswhereusernamelike'__';

前面带%的查询,例如LIKE '%三',普通 B+ 树索引通常很难有效利用,数据量大时要留意执行计划。

3. ORDER BY 排序

selectid,username,balancefromusersorderbybalancedesc,idasc;

先按余额降序;余额相同时,再按id升序。多加一个稳定排序字段,也能避免分页时同分记录顺序来回变化。

4. LIMIT 分页

selectid,username,balancefromusersorderbyidlimit0,10;

n页、每页page_size条时:

offset = (n - 1) × page_size

例如第 3 页、每页 10 条:

selectid,usernamefromusersorderbyidlimit20,10;

也可以写成:

limit10offset20;

当页码非常靠后时,OFFSET会扫描并丢弃大量记录。实际项目常用上一页最后一个id做游标:

selectid,usernamefromuserswhereid>10000orderbyidlimit10;

5. 聚合函数与 GROUP BY

常见聚合函数:

函数用途
count()统计数量
sum()求和
avg()平均值
max()最大值
min()最小值
selectcount(*)asuser_count,round(avg(balance),2)asavg_balance,max(balance)asmax_balancefromusers;

COUNT(*)统计行数;COUNT(phone)只统计phone不为NULL的行。

按状态分组:

selectstatus,count(*)asuser_count,round(avg(balance),2)asavg_balancefromusersgroupbystatus;

先过滤原始行,用WHERE

selectstatus,count(*)asuser_countfromuserswherebalance>=100groupbystatus;

先分组统计,再过滤分组结果,用HAVING

selectstatus,count(*)asuser_countfromusersgroupbystatushavingcount(*)>=2;

6. 几个常用内置函数

-- 日期时间selectcurdate(),now();selectdate_add(curdate(),interval7day);selectdatediff('2026-08-01','2026-07-26');-- 字符串selectconcat(username,':',phone)fromusers;selectchar_length('你好 MySQL');selecttrim(' MySQL ');-- 数学selectround(12.3456,2);selectfloor(rand()*1000000);

中文场景下,CHAR_LENGTH()统计字符数,LENGTH()统计字节数,两者不要混用。

以上是我关于MySQL的笔记分享,也可以关注关注我的Sirens-Blog🥰
感谢你读到这里,这也是我学习路上的一个小小记录。希望以后回头看时,能看到自己的成长~

http://www.jsqmd.com/news/1272036/

相关文章:

  • 【工业级文本摘要Prompt标准】:基于1376份真实业务文档测试,准确率提升41.6%的6大结构范式
  • LLM 效果不好?可能是 Prompt 写错了!
  • 开源模型免费API实战:Llama、Qwen调用指南与工程实践
  • Prompt工程团队组建与管理实战指南
  • C++音频编程实战:从零实现《追光者》音乐合成器
  • Blazor数据可视化实战:ComponentOne趋势线应用
  • 大疆仿真平台面试,Sim2Real迁移这道题难住了九成候选人
  • 2026 年 7 月新发布:河北有实力的基建项目临建房供应厂家怎么联系,你以为它只是临时板房?居然藏着基建项目里少有人知的省钱秘密?-旭华建筑工程 - 行业推荐【认证官】
  • OpenClaw开源工具集:代码分析与自动化处理实战指南
  • 告别臃肿!G-Helper:你的华硕笔记本性能管家,10MB内存搞定一切
  • 鲸鱼算法优化BP神经网络的时间序列预测实践
  • 大数据用户画像系统设计与工程实践
  • 提示词整理效率提升300%的秘诀:用「意图-约束-输出」三维标签法重构你的提示库(附可落地Checklist)
  • TMS320C54x DSP时钟配置实战:PLL原理、CLKMD寄存器详解与避坑指南
  • WebRTC信令系统设计与优化实战指南
  • MATLAB实现电力系统连续潮流分析与PV曲线绘制
  • 动态规划求解最长公共子序列:从原理到C++实现与优化
  • 基于非对称纳什谈判的微电网电能共享Matlab实现
  • 实测盘点:抠图app有哪些值得装、手机免费电脑专业全都有 - 办公小帮手
  • 抖音无水印下载终极教程:3分钟学会批量保存完整视频资源
  • Qwen3.5开源大模型:轻量架构与高效推理实践
  • AIF2硬件限制下软件实现4B/5B编码的快速CM以太网通道
  • AO3镜像站:三步解锁全球最大同人创作平台的终极指南
  • 三足鼎立!国内实景视频孪生三大顶尖技术流派格局
  • C语言函数重载实现:基于_Generic的零开销方案
  • 三天搭建数据分析最小可行系统:Excel+MySQL+Python+PowerBI全流程实战
  • C#贪吃蛇实战:从零构建面向对象游戏引擎与WinForms绘图
  • 小红书视频图片去水印 2026 与第三方风险合规提醒 - 耶斯去水印
  • C语言自增运算符深度解析:从原理到实践,避免常见陷阱
  • Ubuntu服务器搭建Web服务栈:MySQL+Redis+Nginx全流程