本文首发于公众平台:腐烂的橘子
当前很多同学沉迷于“碎片化学习”,问题在于获取到的都是零碎的知识,没有体系化的知识框架,这对于练就扎实的基本功是极其不利的。
怎么办?这时要懂得中庸之道“慢即是快”的道理,系统学一遍,查漏补缺,不要觉得有些你知道就学不下去了,要耐得住性子,系统学习。
下面就来检验下这些知识点你是否都掌握了。
冷知识: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_
这几个等价的关系你了解吗?
如果关联的字段名相同,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
合并两段查询结果。注意两段的列数要相同,下面写法会报错:
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,以第一段查询的列名为准
如果插入其中几个字段,需要写字段,否则可以不写:
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 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()
:求数量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。
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
)
先看一段 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
select *
from invoices
where invoice_total > (
select AVG(invoice_total)
from invoices
where client_id = i.client_id
)
select *
from clients c
where exists (
select client_id
from invoices
where client_id = c.client_id
)
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.73truncate(5.7345, 2)
, 截断,5.73ceiling(5.7)
, 6floor(5.2)
, 5abs(-5.2)
, 5.2rand()
, 0-1 之间的随机值,如 0.6633075453930605length('sky')
,3,字符串长度upper('sky')
, SKYlower('SKy')
, skyltrim(' sky ')
,skyrtrim('sky ')
, skytrim(' sky ')
, skyleft('Kindergarten', 4)
, Kindright('Kinderarara', 6)
, rararasubstring('Kindergarten', 3, 5)
, nderglocate('n', 'Kindergarten')
, 3locate('garten', 'Kindergarten')
, 7replace('Kindergarten', 'garten', 'garden')
, Kindergardenconcat('first', 'last')
, firstlastifnull(shipper_id, 'Not assigned')
:如果 shipper_id 为空,返回 Not assigned。即返回非空值coalesce(shipper_id, comments, 'Not assigned')
:如果 shipper_id 为空,返回 comments,如果 comments,如果 为空,返回 Not assigned。即返回第一个非空值语法: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)
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
假设我们要多次使用一个查询结果:
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文件中,这样可以随时创建视图了。
如果你先创建了视图,但你可能会使用 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
视图的优点是提供了一种抽象,减少了表结构变化带来的影响。