什么是扎实的基本功?MySQL 基础知识看看你了解多少

本文首发于公众平台:腐烂的橘子

当前很多同学沉迷于“碎片化学习”,问题在于获取到的都是零碎的知识,没有体系化的知识框架,这对于练就扎实的基本功是极其不利的。

怎么办?这时要懂得中庸之道“慢即是快”的道理,系统学一遍,查漏补缺,不要觉得有些你知道就学不下去了,要耐得住性子,系统学习。

下面就来检验下这些知识点你是否都掌握了。

关于 join 的那些事

Inner join

冷知识:join = inner join

select order_id, orders.customer_id
from order 
join customers
on orders.customer_id = customers.customer_id

多库连接

可以通过 join 关联其他库表,这是基本用法。

use sql_inventory;

select *
from sql_store.order_items oi
join sql_inventory.products p
on oi.product_id = p.product_id

自连接

join 除了可以关联其他表,也可以关联自己。

use sql_hr;

select a.account_id, a.account_name,b.account_id, b.account_name
from t_account_object a
join t_account_object b
 on a.parent_parent_id = b.account_id

连接超过两张表

不多解释,不断使用 join 就可以了。

use sql_invoicing;

select *
from payments p
join clients c
on p.client_id = c.client_id
join payment_methods pm
on p.payment_ 

outer join

这几个等价的关系你了解吗?

  • inner join 也可写作 join
  • left outer join 也可写作 left join
  • right outer join 也可写作 right outer join

using 怎么用

如果关联的字段名相同,using 可以代替 on。

select
 o.order_id,
 c.first_name
from orders o 
join customers c
 using (customer_id)
join shippers sh
 using (shipper_id)

等价于:

select
 o.order_id,
 c.first_name
from orders o 
join customers c
 on c.customer_id = o.customer_id
join shippers sh
 on sh.shipper_id = o.shipper_id 

如果需要多个字段,用逗号分隔:

select *
from order_items oi
join order_item_notes oin
 using (order_id, product_id)

自然连接

引擎自己选择连接的列,不推荐使用,因为没有显示指明是怎么关联的。

select *
from order o
natual join customers c

交叉连接

返回两张表所有数据行的笛卡尔积,这个一般也不推荐,因为笛卡尔积是指数级别的。

select *
from customers c
cross join products p
order by c.first_name

等价于

select *
from customers c, orders o
order by c.first_name

union

合并两段查询结果。注意两段的列数要相同,下面写法会报错:

select first_name, last_name
from customers
union
select name
from shippers

因为第一段返回一列,第二段返回两列,以下是正确的:

select first_name
from customers
union
select name
from shippers

这里的列名是 first_name,不是 name,以第一段查询的列名为准

varchar 和 char 的区别

  • varchar(50),保存 5 个字符,则没有其余空间
  • char(50),保存 5 个字符,还有 45 个字符空闲

表的创建、更新、删除、查询

insert 一张表

如果插入其中几个字段,需要写字段,否则可以不写:

insert into orders(customer_id, order_date, status) 
values (1, '2019-01-02', 1);
insert into order_items
values
 (LAST_INSERT_ID(), 1, 1, 2.95),
 (LAST_INSERT_ID(), 1, 2, 3.95)

第一个 SQL 加了字段名,第二个没有。

创建表复制

复制整张表:

create table orders_archived as
select * from orders

其中 select * from orders 称为子查询,可以替换成其他复杂的查询语句。

复制其中某几行,还是用 insert into

insert into orders_archived
select *
from orders
where order_date < '2024-01-01'

更新单行

可以设置单行为 null

update invoices
set payment_total = invoice_total * 0.5, payment_date = null
where invoice_id = 1

更新多行

设置 where 选中多行即可。

update 使用子查询

update invoices
set
payment_total = invoice_total * 1.2,
payment_date = due_date
where client_id in (
 select client_id 
 from clients
 where state in ('CA', 'NY')
 )

你一定要知道的聚合函数

数值聚合函数

  • MAX():求最大值
  • MIN():求最小值
  • AVG():求平均值
  • SUM():求和
  • COUNT():求数量

having 和 where 区别

  • where 在分组前筛选
  • having 在分组后筛选

with rollup

select 
 state,
 city,
 sum(invoice_total) as total_sales
from invoices i
join clients c using (client_id)
group by state, city with rollup

生成总计,不能再用 order by。

ALL 关键字

select *
from invoices
where invoice_total > ALL (
 select invoice_total
 from invoices
 where client_id = 3
)

all 和 max 可以替换,比如可以写成这样:

select *
from invoices
where invoice_total > (
 select max(invoice_total)
 from invoices
 where client_id = 3
)

ANY 关键字

先看一段 SQL:

select * 
from clients
where cliend_id in (
 select client_id
 from invoices
 group by client_id
 havind count(*) >= 2
)

用 any 可以这样写:

select * 
from clients
where cliend_id = any (
 select client_id
 from invoices
 group by client_id
 havind count(*) >= 2
)

所以 in 等价于 = any

AVG

select *
from invoices
where invoice_total > (
 select AVG(invoice_total)
 from invoices
 where client_id = i.client_id
)

exists

select *
from clients c
where exists (
 select client_id
 from invoices
 where client_id = c.client_id
)

select 子句中的子查询

select
 invoice_id, 
 invoice_total,
 (select avg(invoice_total)
  from invoice) as invoice_average,
 invoice_total - (select invoice_average) as difference
from invoices

数值函数

  • round(5.7345, 2),四舍五入 5.73
  • truncate(5.7345, 2), 截断,5.73
  • ceiling(5.7), 6
  • floor(5.2), 5
  • abs(-5.2), 5.2
  • rand(), 0-1 之间的随机值,如 0.6633075453930605

字符串函数

  • length('sky'),3,字符串长度
  • upper('sky'), SKY
  • lower('SKy'), sky
  • ltrim(' sky '),sky
  • rtrim('sky '), sky
  • trim(' sky '), sky
  • left('Kindergarten', 4), Kind
  • right('Kinderarara', 6), rarara
  • substring('Kindergarten', 3, 5), nderg
  • locate('n', 'Kindergarten'), 3
  • locate('garten', 'Kindergarten'), 7
  • replace('Kindergarten', 'garten', 'garden'), Kindergarden
  • concat('first', 'last'), firstlast

日期函数

  • now(), 2024-06-23 00:34:04
  • curdate(), 2024-06-23
  • curtime(), 00:34:30
  • year(now()), 2024
  • month(now()), 6
  • day(now()), 23
  • hour(now()), 0
  • minute(now()), 35
  • second(now()), 32
  • dayname(now()), Sunday,字符串格式的星期数
  • monthname(now()), June, 字符串格式的月份
  • extract(year from now()), 2024,标准SQL,推荐使用
  • date_format(now(), ‘%y’), 24,两位数年份
  • date_format(now(), ‘%Y’), 2024,四位数年份
  • date_format(now(), ‘%m’), 06,两位数月份
  • date_format(now(), ‘%M’), June,月份名称
  • time_format(now(), ‘%H:%i %p’), 00:36 AM

计算日期和时间

  • date_add(now(), interval 1 day),返回明天的同一时间
  • date_add(now(), interval 1 year),返回明年的同一时间
  • date_sub(now(), interval -1 year),返回明年的同一时间
  • datediff(‘2024-06-02 09:00’, ‘2024-06-07 17:00’), 5
  • datediff(‘2024-06-07 17:00’, ‘2024-06-02 09:00’), -5
  • time_to_sec(‘09:00’), 32400, 表示从零点流逝的秒数
  • time_to_sec(‘09:00’) - time_to_sec(‘09:02’), -120

ifnull 和 coalesce

  • ifnull(shipper_id, 'Not assigned'):如果 shipper_id 为空,返回 Not assigned。即返回非空值
  • coalesce(shipper_id, comments, 'Not assigned'):如果 shipper_id 为空,返回 comments,如果 comments,如果 为空,返回 Not assigned。即返回第一个非空值

if

语法:if(expression, first, second)

select 
product_id, name, 
count(*) as orders,
if (count(*) > 1, 'Many times', 'Once')
from products
join order_items using (product_id)

case

select 
order_id,
case
 when year(order_date) = year(now()) then 'Active' 
 when year(order_date) = year(now()) - 1 then 'Last Year' 
 when year(order_date) = year(now()) - 1 then 'Archived' 
else 'Future'
end as category

MySQL 视图

创建视图

假设我们要多次使用一个查询结果:

select
 c.client_id, 
 c.name, 
 sum(invoice_total) as total_sales
from clients c
join invoices i using (client_id)
group by client_id, name

可以创建一个视图:

create view sales_by_client as 
select
 c.client_id, 
 c.name, 
 sum(invoice_total) as total_sales
from clients c
join invoices i using (client_id)
group by client_id, name

更改或删除视图

如果想修改视图,有两种办法:

  • 先删除视图,再创建视图
  • 更改视图(更方便)

先删除视图:

drop view sales_by_client

再创建视图:

create view sales_by_client as 
select
 c.client_id, 
 c.name, 
 sum(invoice_total) as total_sales
from clients c
join invoices i using (client_id)
group by client_id, name

或直接使用创建或替换视图,更推荐:

create or replace view sales_by_client as
select
 c.client_id, 
 c.name, 
 sum(invoice_total) as total_sales
from clients c
join invoices i using (client_id)
group by client_id, name

可以把这段sql保存在.sql文件中,这样可以随时创建视图了。

with option check 子句

如果你先创建了视图,但你可能会使用 update 更新视图里的数据,但是视图展示的还是老数据,会造成数据不一致。为了解决这个问题,你可以在视图里添加 with option check 子句,当 update 会更新掉视图的数据时报错,从而解决数据不一致的问题。

create or replace view sales_by_client as
select
 c.client_id, 
 c.name, 
 sum(invoice_total) as total_sales
from clients c
join invoices i using (client_id)
group by client_id, name
with check option

视图的优点是提供了一种抽象,减少了表结构变化带来的影响。

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

腐烂的橘子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值