Appearance
3小时入门sql(基于mysql)
本教程是以该仓库与视频结合的笔记
01.select用法(输出语句)
sql
USE sql_store;
-- 返回客户的所有信息并且按第一个名字字母排序
SELECT *
FROM customers
-- WHERE customer_id = 1
ORDER BY first_name;
-- 返回1,2两行数据
SELECT 1,2
02.as 和distinct 用法 (功能语句)
sql
-- 返回客户的 最后一个名字 第一个名字 积分 折扣
SELECT
last_name,
first_name,
points,
points+10 AS discount_factor
FROM customers;
-- 返回所有客户的地址
SELECT state
FROM customers;
-- 返回所有客户的地址,并消除重复行
SELECT DISTINCT state
FROM customers
AS 用作别名
DISTINCT用作消除重复行
03.select练习
sql
USE sql_store;
-- 用别名 返回所有产品的名称 单价 折扣价
SELECT
`name` ,
unit_price ,
unit_price*1.1 AS 'new price'
FROM products
04.where用法 (判断语句)
sql
-- 积分大于3000的所有客户信息
SELECT *
FROM customers
WHERE points > 3000;
-- 地区在va的所有客户信息
SELECT *
FROM customers
WHERE state = 'va';
-- 地区不在va的客户的所有信息
SELECT *
FROM customers
WHERE state <> 'va';
-- 在1990-01-01年后的客户信息
SELECT *
FROM customers
WHERE birth_date > '1990-01-01';
-- test:获取今年所有的订单
SELECT *
FROM orders
WHERE order_date > '2019';
05.and or not 用法(逻辑语句 : 并 且 非)
sql
-- 查询 客户是九零后或者 积分大于1000并且家在VA
-- AND 的优先级 比 OR高
SELECT *
FROM customers
WHERE birth_date > '1990' OR
(points > 1000 AND state = 'VA');
-- 取反的操作符
SELECT *
FROM customers
WHERE NOT (birth_date > '1999-01-01' OR points > 1000 );
-- 取反等价的
SELECT *
FROM customers
WHERE birth_date <= '1999-01-01' AND points <= 1000;
-- 练习 查询order_items表中 订单id为6的产品总价大于30的记录
SELECT *
FROM order_items
WHERE order_id = 6 AND quantity*unit_price > 30;
06.in用法(逻辑语句 : 包含 离散值)
sql
-- 查询客户在VA或FL或GA
SELECT *
FROM customers
WHERE state = 'VA' OR state = 'FL' OR state = 'GA';
-- 查询客户在VA或FL或GA 用IN的写法
SELECT *
FROM customers
WHERE state IN ('VA','FL','GA');
-- 查询客户不在VA或FL或GA 用IN的写法
SELECT *
FROM customers
WHERE state NOT IN ('VA','FL','GA');
-- 练习:查询products表中库存数是49,38,72
SELECT *
FROM products
WHERE quantity_in_stock IN (49,38,72);
07.between(逻辑语句 : 包含 连续值)
sql
-- 查询积分大于等于1000或者积分小于等于3000之间的客户
SELECT *
FROM customers
WHERE points >= 1000 AND points <= 3000;
-- 用between等价上面的写法
SELECT *
FROM customers
WHERE points BETWEEN 1000 AND 3000;
-- 练习 找出1999到2000出生的用户
SELECT *
FROM customers
WHERE birth_date BETWEEN '1990-01-01' AND '2000-01-01';
08.like 和 % _ 用法(字符串 模糊匹配 占位匹配)
sql
-- 查询以姓名以b(不区分大小写)开头的客户
SELECT *
FROM customers
WHERE last_name LIKE 'b%';
-- 查询以姓名以y(不区分大小写)结尾的客户
SELECT *
FROM customers
WHERE last_name LIKE '%y';
-- 查询以姓名有6个字母,且最后是y的客户
SELECT *
FROM customers
WHERE last_name LIKE '_____y';
-- 练习 获取用户customers地址包含trail 或者 avenue 并电话号码是以9结尾的
SELECT *
FROM customers
WHERE (address LIKE '%trail%' OR address OR '%avenue%' )
AND phone LIKE '%9';
-- 电话不是以9结尾的客户
SELECT *
FROM customers
WHERE phone NOT LIKE '%9';
09.REGEXP用法(字符串 正则匹配)
sql
-- 搜索姓名中带有field的客户
SELECT *
FROM customers
WHERE last_name LIKE '%field%';
-- 用正则来实现上述功能
SELECT *
FROM customers
WHERE last_name REGEXP 'field';
-- 姓名以field开头的客户
SELECT *
FROM customers
WHERE last_name REGEXP '^field';
-- 姓名以field结尾的客户
SELECT *
FROM customers
WHERE last_name REGEXP 'field$';
-- 姓名带有field或mac或rose的客户
SELECT *
FROM customers
WHERE last_name REGEXP 'field|mac|rose';
-- 姓名带以field开头或带有mac或rose的客户
SELECT *
FROM customers
WHERE last_name REGEXP '^field|mac|rose';
-- 姓名带有 ge ie me的客户
SELECT *
FROM customers
WHERE last_name REGEXP '[gim]e';
-- 姓名带有 eg ei em的客户
SELECT *
FROM customers
WHERE last_name REGEXP 'e[gim]';
-- 姓名带有 e且e前面包含a到h的任一字母的客户
SELECT *
FROM customers
WHERE last_name REGEXP '[abcdefgh]e';
-- 等价上述写法
SELECT *
FROM customers
WHERE last_name REGEXP '[a-h]e';
10.regexp练习
sql
-- 练习1:找出first_name名字是elka或者ambur的
SELECT *
FROM customers
WHERE first_name REGEXP 'elka|ambur';
-- 练习2:检索last_name名字是以ey或者on结尾的
SELECT *
FROM customers
WHERE last_name REGEXP 'ey$|on$';
-- 练习3:检索last_name名字是以my开头或者包含se的客户
SELECT *
FROM customers
WHERE last_name REGEXP '^my|se';
-- 练习4:获取last_name名字包含b紧跟r或者u
SELECT *
FROM customers
WHERE last_name REGEXP 'b[ru]';
11.is null用法(判空)
sql
-- 查询没有填写的电话的用户
SELECT *
FROM customers
WHERE phone IS NULL;
-- 查询填写的电话的用户
SELECT *
FROM customers
WHERE phone IS NOT NULL;
-- 练习:查询没有发货的订单
SELECT *
FROM orders
WHERE shipped_date IS NULL;
12.order by用法(排序)
sql
-- 默认排序是以id来排的,因为id是主键
SELECT *
FROM customers;
-- 以名称正序排序
SELECT *
FROM customers
ORDER BY first_name;
-- 以名称倒序排序
SELECT *
FROM customers
ORDER BY first_name DESC;
-- 以多列查询
-- 以名称和州名正序排序
SELECT *
FROM customers
ORDER BY first_name,state;
-- 以多列查询
-- 以名称和州名倒序排序
SELECT *
FROM customers
ORDER BY first_name DESC,state DESC;
-- 可以是不查询的列作为排序
SELECT first_name,last_name
FROM customers
ORDER BY birth_date;
-- 用别名进行排序
SELECT first_name,last_name,10 AS points
FROM customers
ORDER BY points,first_name;
-- 用选取列的位置进行排序
-- 下列的含义就是first_name和last_name
-- 尽量不要使用,如果选取的列就会改变排序顺序
SELECT first_name,last_name,10 AS points
FROM customers
ORDER BY 1,2;
-- 练习
SELECT order_id,product_id,quantity,unit_price,quantity*unit_price AS 'all price'
FROM order_items
WHERE order_id = 2
ORDER BY quantity*unit_price DESC;
-- 写法2
SELECT *,quantity*unit_price AS 'all price'
FROM order_items
WHERE order_id = 2
ORDER BY 'all price' DESC;
13.limit用法( 限制输出 与select配合)
sql
-- 选择头3个用户
SELECT *
FROM customers
LIMIT 3;
-- 偏移量
-- 分页,一页有3个用户
-- page1 1-3 page2 4-6 page3 7-9
-- 返回page3就需要偏移6位,每页3个
SELECT *
FROM customers
LIMIT 6,3;
-- 找出前3个积分最高的用户
SELECT *
FROM customers
ORDER BY points DESC
LIMIT 3;
-- 注意子句的顺序,select ,from ,where, order by,limit
14.join(inner join)用法( 多表查询)
sql
USE sql_store;
-- 多表查询
-- 一张表需要连接另一张表,之所以信息要分开写是因为如果要写在一张表中
-- 那如果更改了一个客户信息,那么所有的订单都要修改对应所有的信息,所以要分开写,连接靠id
-- 连接join + 连接的表名 on +连接的条件
-- INNER JOIN 和 JOIN 是一样的
SELECT *
FROM orders
JOIN customers
ON orders.customer_id = customers.customer_id;
-- 多表输出指定的列
-- 不同的表的相同列需要带上表名
SELECT order_id, orders.customer_id, first_name, last_name
FROM orders
JOIN customers
ON orders.customer_id = customers.customer_id;
-- 使用别名
SELECT order_id, o.customer_id, first_name, last_name
FROM orders o
JOIN customers
ON o.customer_id = customers.customer_id;
-- 使用别名
SELECT order_id, o.customer_id, first_name, last_name
FROM orders o
JOIN customers c
ON o.customer_id = c.customer_id;
-- 练习:订单order_items和产品表products
-- 注意用别名后只能表只能用别名了,其他的不行
SELECT o.order_id, o.quantity, o.unit_price, o.quantity*o.unit_price AS 'total_price',p.product_id,p.`name`,p.unit_price
FROM order_items o
JOIN products p
ON o.product_id = p.product_id;
-- join可以跨库查询
SELECT *
FROM order_items o
JOIN sql_inventory.products p
ON o.product_id = p.product_id;
-- join可以连接同一个表
-- 此处右边为null的自动删除
USE sql_hr;
SELECT
e.employee_id,
e.first_name,
m.first_name AS 'manager'
FROM employees e
JOIN employees m
ON e.reports_to = m.employee_id;
-- join 连接多个表
USE sql_store;
SELECT
o.order_id,
o.order_date,
c.first_name,
c.last_name,
os.`name` AS `status`
FROM orders o
JOIN customers c
ON o.customer_id = c.customer_id
JOIN order_statuses os
ON o.`status` = os.order_status_id;
-- 练习: join 连接多个表
USE sql_invoicing;
SELECT
p.`date`,
c.`name`,
p.invoice_id,
p.amount,
pm.`name` AS 'paymethod'
FROM payments p
JOIN clients c
ON p.client_id = c.client_id
JOIN payment_methods pm
ON p.payment_method = pm.payment_method_id;
-- 连接带有复合主键的表
USE sql_store;
SELECT *
FROM order_items oi
JOIN order_item_notes oin
ON oi.order_id = oin.order_id
AND oi.product_id = oin.product_id;
15.inner join on隐式写法(inner join on的简写)
sql
-- join连接表的隐式写法
-- 直接from多个表,在where中写连接条件
SELECT *
FROM orders o, customers c
WHERE o.customer_id = c.customer_id;
-- 如果没有写where的连接条件就是交叉表(笛卡尔积)
SELECT *
FROM orders o, customers c
16.外连接 right join和left join
mysql有两种连接方式 外连接和内连接
- 内连接只返回复合连接条件的数据
- 外连接无论符不符合都会返回
外连接有两种方式
- right join 返回所有右边的表
- left join 返回所有左边的表
sql
-- mysql有两种连接方式 外连接和内连接
-- 内连接只返回复合连接条件的数据
-- 外连接无论符不符合都会返回
-- 外连接有两种方式
-- 当是right join 返回所有右边的表
-- 当是left join 返回所有左边的表
USE sql_store;
-- 内连接
SELECT
c.customer_id,
c.first_name,
o.order_id
FROM customers c
JOIN orders o
ON c.customer_id = o.customer_id
ORDER BY c.customer_id;
-- 外连接
SELECT
c.customer_id,
c.first_name,
o.order_id
FROM customers c
LEFT JOIN orders o
ON c.customer_id = o.customer_id
ORDER BY c.customer_id;
-- 练习:合并产品表和订单产品表
SELECT p.product_id,p.`name`,oi.quantity
FROM products p
LEFT JOIN order_items oi
ON p.product_id = oi.product_id;
-- 多表外连接 外连接客户表 订单表 物流表
-- 少用右连接,保持连接一致性
SELECT
c.customer_id,
c.first_name,
o.order_id,
sh.`name` AS shipper
FROM customers c
LEFT JOIN orders o
ON c.customer_id=o.customer_id
LEFT JOIN shippers sh
ON o.shipper_id = sh.shipper_id
ORDER BY c.customer_id;
-- 练习: 订单表 order customers shippers order_statuses
SELECT
o.order_date,
o.order_id,
c.first_name,
sh.`name` AS 'shipper',
os.`name` AS 'status'
FROM orders o
JOIN customers c
ON c.customer_id=o.customer_id
LEFT JOIN shippers sh
ON o.shipper_id = sh.shipper_id
LEFT JOIN order_statuses os
ON o.`status` = os.order_status_id
ORDER BY o.order_id;
-- 外连接同一张表
USE sql_hr;
SELECT
e.employee_id,
e.first_name,
m.first_name AS manager
FROM employees e
LEFT JOIN employees m
ON e.reports_to = m.employee_id;
17.using子句(on的连接条件另一种写法)
sql
-- 使用on的连接条件会让sql看起来难懂
USE sql_store;
SELECT *
FROM order_items oi
JOIN order_item_notes oin
ON oi.order_id = oin.order_id AND
oi.product_id = oin.product_id;
-- 使用using子句代替上述操作
SELECT *
FROM order_items oi
JOIN order_item_notes oin
USING (order_id,product_id);
-- 简化
SELECT
o.order_id,
c.first_name,
sh.`name` AS shipper
FROM orders o
JOIN customers c
USING (customer_id)
LEFT JOIN shippers sh
USING (shipper_id);
-- 练习:
USE sql_invoicing;
SELECT
p.date,
c.`name`,
p.amount,
pm.`name`
FROM payments p
JOIN clients c
USING (client_id)
JOIN payment_methods pm
ON p.payment_method = pm.payment_method_id;
18. natural join(其他的连接类型:自然连接 自动识别连接条件,不用去写on连接条件)
sql
-- 数据库会自动识别相同的字段并连接
-- 不推荐这样写
SELECT
o.order_id,
c.first_name
FROM orders o
NATURAL JOIN customers c
19.cross join(其他的连接类型:交叉连接 笛卡尔积)
sql
-- 交叉连接(笛卡尔积)
SELECT
c.first_name AS customer,
p.`name` AS product
FROM customers c
CROSS JOIN products p
ORDER BY c.first_name;
-- 隐式交叉连接
SELECT
c.first_name AS customer,
p.`name` AS product
FROM customers c,products p
ORDER BY c.first_name;
-- 练习 将shippers和products表进行显示连接和隐式连接
-- 写法1:隐式写法
SELECT *
FROM products p,shippers s
ORDER BY p.product_id;
-- 写法2:显示写法
SELECT *
FROM products p
CROSS JOIN shippers s
ORDER BY p.product_id
20.union 用法(聚合多个查询结果到一张表)
sql
-- UNION 增加表的行
-- 现在有两个查询
-- 查询1 有效订单
SELECT
order_id,
order_date,
'Active' AS 'status'
FROM orders
WHERE order_date >= '2019-01-01';
-- 查询2 归档订单
SELECT
order_id,
order_date,
'Archived' AS 'status'
FROM orders
WHERE order_date < '2019-01-01';
-- union合并两个查询到一张表上
SELECT
order_id,
order_date,
'Active' AS 'status'
FROM orders
WHERE order_date >= '2019-01-01'
UNION
SELECT
order_id,
order_date,
'Archived' AS 'status'
FROM orders
WHERE order_date < '2019-01-01';
-- 练习
SELECT
customer_id,
first_name,
points,
'Gold' AS 'type'
FROM customers
WHERE points >=3000
UNION
SELECT
customer_id,
first_name,
points,
'Sliver' AS 'type'
FROM customers
WHERE points >=2000 AND points < 3000
UNION
SELECT
customer_id,
first_name,
points,
'Bronze' AS 'type'
FROM customers
WHERE points < 2000
ORDER BY first_name;
21.insert 用法(插入数据到表)
sql
-- 插入数据表
-- DEFAULT是让数据库填入默认值
USE sql_store;
INSERT INTO customers
VALUES (
DEFAULT,
'Lion',
'Lee',
'1999-01-01',
NULL,
'address',
'city',
'CA',
DEFAULT
);
-- 插入方式2
INSERT INTO customers(
first_name,
last_name,
birth_date,
address,
city,
state
)
VALUES (
'Lion2',
'Lee',
'1999-01-01',
'address',
'city',
'CA'
);
-- 插入多条数据
INSERT INTO shippers (name)
VALUES ('Shipper1'),
('Shipper2'),
('Shipper3');
-- 练习:向产品表中添加3条产品记录
INSERT INTO products (
`name`,
quantity_in_stock,
unit_price
)
VALUES ('drink',11,5.0),
('noodles',5,10.0),
('fruit',100,3.0);
-- 向关联表插入数据,
-- 添加订单记录以及订单中的产品
INSERT INTO orders(customer_id,order_date,`status`)
VALUES (1,'2019-01-02',1);
-- 最后插入成功数据的id
-- SELECT LAST_INSERT_ID();
INSERT INTO order_items
VALUES
(LAST_INSERT_ID(),1,1,2.1),
(LAST_INSERT_ID(),2,1,2.95)
22.create table as 用法(复制表)
sql
-- 复制一个表
CREATE TABLE orders_archived AS
SELECT * FROM orders;
-- 用这种方法复制的表,没有主键和自动增加属性
-- 复制一个表的部分数据
INSERT INTO orders_archived
SELECT *
FROM orders
WHERE order_date < '2019-01-01';
-- 练习:
USE sql_invoicing;
CREATE TABLE invoices_archived AS
SELECT
i.invoice_id,
i.number,
c.`name`,
i.invoice_total,
i.payment_total,
i.invoice_date,
i.due_date,
i.payment_date
FROM invoices i
JOIN clients c
USING(client_id)
WHERE i.payment_date IS NOT NULL;
23.update 用法(修改表)
sql
-- 更新一条数据
USE sql_invoicing;
SELECT * FROM sql_invoicing.invoices;
UPDATE invoices
SET payment_total = 10,
payment_date = '2019-03-01'
WHERE invoice_id = 1
-- 更新一条数据,使用默认值
UPDATE invoices
SET
payment_total = DEFAULT,
payment_date = '2019-03-01'
WHERE invoice_id = 1;
-- 更新一条数据,插入对应的字段
USE sql_invoicing;
UPDATE invoices
SET
payment_total = invoice_total*0.5,
payment_date = due_date
WHERE invoice_id = 3;
-- 更新多条数据
-- 只要条件满足多个就会自动更新
-- 更新全部把where去掉即可
UPDATE invoices
SET
payment_total = invoice_total*0.5,
payment_date = due_date
WHERE client_id IN (3,4);
-- 练习
-- 给所有1990年以前的用户多加50积分
USE sql_store;
UPDATE customers
SET points = points+50
WHERE birth_date <'1990-01-01';
-- 通过子查询来更新数据
-- 在执行更新操作前,看一看子操作是什么
USE sql_invoicing;
UPDATE invoices
SET
payment_total = invoice_total*0.5,
payment_date = due_date
WHERE client_id = (
SELECT client_id
FROM clients
WHERE `name` = 'Myworks'
)
-- 有条件更新当前的表,直接加where
USE sql_invoicing;
UPDATE invoices
SET
payment_total = invoice_total*0.5,
payment_date = due_date
WHERE payment_date IS NULL;
-- 练习:更新orders的积分大于3000的客户comments为金牌客户gold customers
USE sql_store;
UPDATE orders
SET
comments = 'Gold Customer'
WHERE customer_id IN
(
SELECT customer_id
FROM customers
WHERE points >= 3000
)
24.delete 用法(删除表)
sql
-- delete 删除1行
-- 如果不写where则会删除表中所有的数据
USE sql_invoicing;
DELETE FROM invoices
WHERE invoice_id = 1;