跟Mosh老师学SQL的第一天 - 子句和运算符

130 阅读5分钟

第一部分:基础知识

SQL语句的书写方式是:大写SQL关键字➕其他地方都小写;
每当你有很多条SQL语句时,你需要用分号来终止每条语句;
-- 就是注释的写法,SQL就不会执行它们;
在SQL中,换行符/大间隔/tab符号都不会被执行
USE sql_store;

SELECT *
FROM customers
-- WHERE customer_id = 1
ORDER BY first_name

在MySQL中可以用双击/USE➕表名两种方式来选中不同的数据库

SELECT 之后要指定列名,或者我们可以用*来选中所有列

WHERE语句用于筛选结果

ORDER BY语句用于给数据排序,在ORDER BY语句之后,需要指定排序结果参照的列

子句的顺序(SELECT -> FROM -> WHERE -> OEDER BY)不可被改变,否则就会出现语法错误,如果SQL语句的语义语法或者结构不正确,那么它将无法被执行

第二部分:the SELECT Clause

USE sql_store;

SELECT 
    last_name, 
    first_name, 
    points, 
    points * 10 + 100 AS discount_factor
FROM customers

SELECT Clause的语句中可以使用加法,减法,乘法,除法,取模(也就是除法的余数),在算数表达式中,运算符的顺序是基于数学中的运算符次序

AS关键字可以用于修改列名,给列和结果集一个描述性名称,如果AS后的列名中需要空格,那么则需要在列名两侧加入单引号/双引号

如果想在结果集中得到一份查询结果的唯一列表,只需要在SELECT关键字之后加入DISTINCT关键字,即可帮助查询去除重复项

USE sql_store;

SELECT DISTINCT state
FROM customers

EXERCISE:

-- Return all the products

-- name
-- unit price
-- new price (unit price * 1.1)

SOLUTION:

USE sql_store

SELECT name, unit_price, unit_price * 1.1 AS "unit price"
FROM products

第三部分:the WHERE Clause

USE sql_store;

SELECT *
FROM customers
WHERE points > 3000

运算符包括:>, >=, <, <=, != or <> is not equal

运算符后面可以接字符串,但是需要加单引号/双引号,一般是用单引号,字符串的大小写是无关紧要的

有一个例外是引号表述日期值,即使日期不算是字符串。

EXERCISE:

-- Get the orders placed this year

SOLUTION:

USE sql_store;

SELECT *
FROM orders
WHERE order_date >= '2019-01-01'

第四部分:AND, OR NOT运算符

SELECT *
FROM Customers
WHERE birth_date > '1990-01-01' AND points > 1000
///
WHERE birth_date > '1990-01-01' OR points > 1000
///
WHERE birth_date > '1990-01-01' OR points > 1000 AND state = 'VA'

在算数运算符的顺序中,* 和 / 优先于 + 和 -
也可以用括号来改写默认的顺序,逻辑运算符也是一样的概念
AND运算符总是被优先考虑,执行查询的时候,查询执行引擎将首先评估AND条件,所以我们可以在后两个条件上面加上括号,让代码看起来更加清晰

SELECT *
FROM Customers
WHERE birth_date > '1990-01-01' OR (points > 1000 AND state = 'VA')

NOT运算符用于否定一个条件
例子如下:

SELECT *
FROM Customers
WHERE NOT (birth_date > '1990-01-01' OR points > 1000)
///
WHERE birth_date <= '1990-01-01' AND points <= 1000

EXERCISE:

-- From the order_items table, get the items
--      from order #6
--      where the total price is greater than 30

SOLUTION:

USE sql_store;

SELECT *
FROM order_items
WHERE order_id = 6 AND unit_price * quantity > 30

第五部分:IN运算符

USE sql_store;

SELECT *
FROM Customers
WHERE state = ‘VA’ OR state = ‘GA’ OR state = ‘FL’

使用IN运算符的写法

USE sql_store;

SELECT *
FROM Customers
WHERE state IN (‘VA’, ‘GA’, ‘FL’)
///
WHERE state NOT IN (‘VA’, ‘GA’, ‘FL’)

EXERCISE:

-- Return products with
--      quantity in stock equal to 49, 38, 72

SOLUTION:

USE sql_store;

SELECT *
FROM products
WHERE quantity_in_stock IN (49, 38, 72)

第六部分:BETWEEN运算符

USE sql_store;

SELECT *
FROM customers
WHERE points >= 1000 AND points <= 3000

使用BETWEEN运算符的写法

USE sql_store;

SELECT *
FROM customers
WHERE points BETWEEN 1000 AND 3000

EXERCISE:

-- Return customers born
--      between 1/1/1990 and 1/1/2000

SOLUTION:

USE sql_store;

SELECT *
FROM customers
WHERE birth_date BETWEEN '1990-01-01' AND '2000-01-01'

第七部分:LIKE运算符

USE sql_store;

SELECT *
FROM customers
WHERE last_name LIKE 'b%'
/// 在这里无论b是大写还是小写都无所谓
USE sql_store;

SELECT *
FROM customers
WHERE last_name LIKE '%b%'
/// 在这里无论b是大写还是小写都无所谓
USE sql_store;

SELECT *
FROM customers
WHERE last_name LIKE '%y'
/// 在这里无论b是大写还是小写都无所谓

使用下面的语句可以获得姓氏正好为2个字符串的长度的顾客

USE sql_store;

SELECT *
FROM customers
WHERE last_name LIKE '_y'
/// 在这里无论b是大写还是小写都无所谓

综上所述: % means any number of characters, _ means single character

EXERCISE:

-- Return customers whose
--      adress contain TRAIL or AVENUE
--      phone numbers end with 9

SOLUTION_first:

USE sql_store;

SELECT *
FROM customers
WHERE address LIKE '%trail%' OR
      address LIKE '%avenue%'

SOLUTION_second:

USE sql_store;

SELECT *
FROM customers
WHERE phone LIKE '%9'

第八部分:REGEXP运算符

USE sql_store;

SELECT *
FROM customers
WHERE last_name LIKE '%field%'
WHERE last_name REGEXP 'field'
USE sql_store;

SELECT *
FROM customers
WHERE last_name REGEXP '^field'
/// 这样的正则表达式表示顾客的姓氏必须以field打头
WHERE last_name REGEXP 'field$'
/// 这样的正则表达式表示顾客的姓氏必须以field结尾
WHERE last_name REGEXP 'field|mac|rose'
/// 这样的正则表达式表示顾客的姓氏必须包含field或者mac或者rose
WHERE last_name REGEXP '[gim]e'
/// 这样的正则表达式表示顾客的姓氏必须包含ge或者ie或者me
WHERE last_name REGEXP '[a-h]e'
/// 这样的正则表达式表示顾客的姓氏必须包含ae-he的各种组合

EXERCISE:

-- Return customers whose
--      first names are ELKA or AMBUR
--      last names end with EY or ON
--      last names start with MY or contains SE
--      last names contain B followed by R or U

SOLUTIONS:

USE sql_store;

SELECT *
FROM customers
WHERE first_name REGEXP 'elka|ambur'
///
WHERE first_name REGEXP 'ey$|on$'
///
WHERE last_name REGEXP '^my|se'
///
WHERE last_name REGEXP 'b[ru]'
///
WHERE last_name REGEXP 'br|bu'

第九部分:IS、NULL运算符

USE sql_store;

SELECT *
FROM customers
WHERE phone IS NULL
///
WHERE phone IS NOT NULL

EXERCISE:

-- Get the orders that are not shipped

SOLUTION:

USE sql_store;

SELECT *
FROM orders
WHERE shipper_id IS NULL

第十部分:ORDER BY子句

USE sql_store;

SELECT *
FROM customers
ORDER BY first_name DESC
/// 默认情况下是根据这张表的 primary key来排序的
/// DESC 降序

ORDER BY state, first_name
/// 首先我们想根据州来给顾客排序,然后在每个州里,根据名字排序

MySQL与其他数据库管理系统的一个区别是:
MySQL中你可以用任何列排序数据,不管那列是不是在SELECT子句中
例如:

USE sql_store;

SELECT first_name, last_name
FROM customers
ORDER BY birth_date DESC
/// 这样的写法只在MySQL中正确

/// ORDER BY 后也可以只跟12这样的数字
/// 这即意味着依据第一和第二列排序数据
/// 但是应该避免这样书写SQL,因为列会变化

EXERCISE: image.png

-- 写一个查询
-- 选择所有order id为2的项目
-- 根据总价格来降序排列

SOLUTION:

USE sql_store;

SELECT *
FROM order_items
WHERE order_id = 2
ORDER BY quantity * unit_price DESC

SOLUTION_2:

USE sql_store;

SELECT *, quantity * unit_price AS total_price
FROM order_items
WHERE order_id = 2
ORDER BY total_price DESC

第十一部分:LIMIT子句

USE sql_store;

SELECT *
FROM customers
LIMIT 3
/// 这样就可以只返回前3位顾客
/// 如果这个数字大于了表中数据的数量,那么就会返回全部数据

LIMIT通常用于数据的分页,例如

page1: 1 - 3
page2: 4 - 6
page3: 7 - 9
如果现在想跳过前6条数据,获得7 - 9,该如何写SQL呢?

SOLUTION:

USE sql_store;

SELECT *
FROM customers
LIMIT 6, 3
/// 这样就可以只返回前3位顾客
/// 如果这个数字大于了表中数据的数量,那么就会返回全部数据
/// 6被我们称为偏移量

EXERCISE:

-- Get the top three loyal customers, 也就是积分最多的三个顾客

SOLUTION:

USE sql_store;

SELECT *
FROM customers
ORDER BY points DESC
LIMIT 3
/// LIMIT子句永远在最后

在我们已经学习的子句中,标准的顺序是如下的例子:

USE sql_store;

SELECT *
FROM 
WHERE
ORDER BY 
LIMIT 
/// LIMIT子句永远在最后