【MySQL】2.基本语句
【MySQL2】基本语句
导入数据库
教程https://www.yiibai.com/mysql/how-to-load-sample-database-into-mysql-database-server.html
表与表之间的关系如下:
注意最后的查询语句 offices 没有引号。
查询语句
从一个或多个表中检索信息。
使用select语句,必须至少给出两条信息——想选择什么,从什么地方选择:
select prod_name from products;
输出如下:
说明:未排序数据——显示输出的数据顺序每次不同。如果没有明确排序查询结果,则返回的数据没有特定的顺序。返回数据的顺序可能是数据被添加到表中的顺序,也可能不是,只要返回相同数目的行就可以。
注意:
-
多条SQL语句必须以分号(;)相隔
-
sql不区分大小写,许多开发人员习惯 关键字大写,对列名和表名使用小写。
-
使用空格:SQL的所有空格都被忽略,SQL语句可以写成长长的一行,也可以分写在多行。
检索多个列
在select关键字后给出多个列名,列名之间必须以逗号分隔。最后一个列名不要加。
select prod_ID,prod_name,prod_price
from products;
检索所有列
在实际列名的位置使用星号(*)通配符:
select*
from products;
使用通配符可以检索出未知列。
去重语句
select vend_id from products;
select语句返回9行(表中只有3个供应商),因为products表中有9种产品。
检索出不同的值:使用DISTINCT关键字——指示数据库只返回不同的值。
select DISTINCT vend_id
from products;
注意:distinct关键字作用于所有的列,不仅仅是跟在其后的那一列。例如,你指定SELECT DISTINCT vend_id,prod_price,除非指定的两列完全相同,否则所有的列都会被检索出来。
前N个语句
只想返回第一行或者一定数量的行,不过不同的数据库的SQL实现不同。
在 SQL Server和 Access中使用SELECT时,可以使用top关键字来限制最多返回多少行:
SELECT TOP 5 prod_name
FROM Products;
如果使用的是DB2:
SELECT prod_name
FROM Products
FETCH FIRST 5 ROWS ONLY;
如果使用Oracle,需要基于rownum来计算行:
SELECT prod_name
FROM Products
WHERE ROWNUM <=5;
如果你使用 MySQL、MariaDB、PostgreSQL或者 SQLite,需要使用LIMIT子句,像这样:
select prod_name
from products
limit 5;
指定从哪开始以及检索的行数:
select prod_name
from products
limit 5 offset 5;
返回从第5行起的5行数据。
注意:第一个被检索的行是第0行,所以limit 1 offset 1会检索第2行,而不是第1行。
MySQL支持简化版语句:limit3,4。逗号之前的值对应offset,之后的值对应limit。
CASE…END语句
SELECT
case -------------如果
when sex=‘1’ then ‘男’ -------------sex=‘1’,则返回值’男’
when sex=‘2’ then ‘女’ -------------sex=‘2’,则返回值’女’
else 0 -------------其他的返回’其他’
end -------------结束
from sys_user --------整体理解: 在sys_user表中如果sex=‘1’,则返回值’男’如果sex=‘2’,则返回值’女’ 否则返回’其他’
注释
解释复杂的语句,还有一个重要应用是:暂时停止要执行的代码。如果你碰到一个长SQL语句,而只想测试它的一部分,那么应该注释掉一些代码。
SELECT prod_name -- 这是一条注释
FROM Products;
# 这是一条注释
SELECT prod_name
FROM Products;
/* SELECT prod_name, vend_id
FROM Products; */
SELECT prod_name
FROM Products;
注释从 / * 开始,到* /结束,/ * 和* /之间的任何内容都是注释。这种方式常用于给代码加注释。
排序语句
子句:一个子句通常由一个关键字加上所提供的数据组成。子句的例子有我们在前一课看到的 SELECT 语句的 FROM 子句。
ORDER BY子句去一个或多个列的名字,据此对输出进行排序。
SELECT prod_name
FROM Products
ORDER BY prod_name;
注意:在指定一条order by子句时,应该保证它是SELECT语句中最后一条子句。否则会出现错误消息。
按多个列排序
经常需要按不止一个列进行数据排序。例如,按性和名排序来显示雇员名单。
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price, prod_name;
代码检索3个列,并按其中两个列对结果进行排序——首先按价格,然后按名称排序。
按列位置排序
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY 2, 3;
SELECT 清单中指定的是选择列的相对位置而不是列名。ORDER BY 2表示按 SELECT 清单中的第二个列 prod_name 进行排序。ORDER BY 2,3 表示先按 prod_price,再按 prod_name 进行排序。
这一技术的好处在于不用重新输入列名。
指定排序方向
升序排序(A~Z)只是默认的排序顺序,还可以降序排序。使用DESC关键字。
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC;
打算用多个列排序:
SELECT prod_id, prod_price, prod_name
FROM Products
ORDER BY prod_price DESC, prod_name;
DESC关键字只应用到直接位于其前面的列名。在上例中,只对city列指定 DESC,对 state 列不指定。因此,city 列以降序排序,而 state 列(在每个价格内)仍然按标准的升序排序。
提示:在字典排序顺序中,A被视为和a一样,这是大多数数据管理系统的默认行为。但是,许多DBMS允许数据库管理员在需要时改变这种行为。
筛选语句
使用where子句
只检索所需数据需要指定搜索条件,搜索条件也称为过滤条件。
select city,state
from offices
where city="NYC";
注意,要对指定的内容加引号(单双都可以),否则会报错!
位置:在使用order by和where 子句时,应该让 order by位于where 之后。
检查单个值
SELECT prod_name, prod_price
FROM Products
WHERE prod_price < 10;
是列出所有价格小于 10 美元的产品。
不匹配检查
SELECT vend_id, prod_name
FROM Products
WHERE vend_id <> 'DLL01';
列出所有不是供应商 DLL01 制造的产品。!=和<>可以互换,但并非所有DBMS支持这两种操作符。
范围值检查
要检查某个范围的值,可以使用BETWEEN操作符。他需要两个值。
SELECT prod_name, prod_price
FROM Products
WHERE prod_price BETWEEN 5 AND 10;
在使用 BETWEEN 时,必须指定两个值——所需范围的低端值和高端值。这两个值必须用 AND 关键字分隔。BETWEEN 匹配范围中所有的值,包括指定的开始值和结束值。
空值检查
在创建表时,表设计人员可以指定其中的列能否不包含值。在一个列不包含值时,称其包含空值NULL。
注意正确的语法书写:是IS NULL。
高级数据过滤
组合where子句
为了进行更强的过滤控制,SQL 允许给出多个 WHERE 子句。这些子句有两种使用方式,即以 AND 子句或 OR 子句的方式使用。
AND操作符
SELECT prod_id, prod_price, prod_name
FROM Products
WHERE vend_id = 'DLL01' AND prod_price <= 4;
OR操作符
OR 操作符与 AND 操作符正好相反,它指示 DBMS 检索匹配任一条件的行。事实上,许多 DBMS 在 OR WHERE 子句的第一个条件得到满足的情况下,就不再计算第二个条件了。
求值顺序
where子句可以包含任意数目的AND和OR操作符。允许两者结合以进行复杂、高级的过滤。
SELECT prod_name, prod_price
FROM Products
WHERE vend_id = 'DLL01' OR vend_id = 'BRS01'
AND prod_price >= 10;
返回的行中有 4 行价格小于 10 美元,这是因为AND的优先级高于OR,所以操作符被错误的组合了。此问题的解决方法是使用圆括号对操作符进行明确分组。
IN操作符
IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN 取一组由逗号分隔、括在圆括号中的合法值。下面的例子说明了这个操作符。
SELECT prod_name, prod_price
FROM Products
WHERE vend_id IN ( 'DLL01', 'BRS01' )
ORDER BY prod_name;
IN操作符完成了与OR相同的功能。使用IN有以下优点:
- 在有很多合法选项时,IN 操作符的语法更清楚,更直观。
- 在与其他 AND 和 OR 操作符组合使用 IN 时,求值顺序更容易管理。
- IN 操作符一般比一组 OR 操作符执行得更快(在上面这个合法选项很少的例子中,你看不出性能差异)。
- IN 的最大优点是可以包含其他 SELECT 语句,能够更动态地建立WHERE 子句。
NOT操作符
WHERE 子句中的 NOT 操作符有且只有一个功能,那就是否定其后所跟的任何条件。NOT 关键字可以用在要过滤的列前,而不仅是在其后。
SELECT prod_name
FROM Products
WHERE NOT vend_id = 'DLL01'
ORDER BY prod_name;
上面的例子也可以用<>操作符来完成。
用通配符进行过滤
LIKE操作符
前面介绍的操作符都是针对已知值进行过滤的,但在有些情况下并不适用。例如,怎么搜索产品中包含文本bean bag的所有产品?必须使用通配符。
利用通配符,可以创建比较特定数据的搜索模式。
(%)通配符
在搜索串中,% 表示任何字符出现任意次数。例如,为了找出所有以词 Fish 起头的产品,可发布以下 SELECT 语句:
SELECT prod_id, prod_name
FROM Products
WHERE prod_name LIKE 'Fish%';
注意NULL空值不算在这里面。
通配符可在搜索模式中的任意位置使用,并且可以使用多个通配符。下面的例子使用两个通配符,位于模式的两端。
SELECT prod_id, prod_name
FROM Products
WHERE prod_name LIKE '%bean bag%';
有一种情况吧通配符防在中间是很有用的,就是根据邮件地址的一部分来查找电子邮件,例如WHERE email LIKE ‘b%@forta.com’。
除了可以匹配一个或多个字符外,% 还可以匹配0个字符。
%不会匹配产品名称为 NULL的行。
下划线(_)通配符
下划线的用途和%一样,但它只匹配单个字符,而不是多个字符。
方括号([])通配符
用来指定一个数据集,必须匹配指定位置的一个字符。
例如,找出所有名字以 J 或 M 起头的联系人,可进行如下查询:
SELECT cust_contact
FROM Customers
WHERE cust_contact LIKE '[JM]%'
ORDER BY cust_contact;
在MySQL中[]不管用。
使用通配符的技巧
不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符。
尽量不要把它们用在搜索模式的开始出,这样搜索是最慢的。
仔细注意通配符的位置。
创建计算字段
计算字段
存储在数据库中的数据一般不是应用程序所需要的格式,如下面的例子:
- 需要显示公司名,同时还需要显示公司的地址,但这两个信息存储在不同的列表中;
- 城市、州和邮政编码存储在不同的列中,但邮件标签打印程序需要把它们作为一个有恰当格式的字段检索出来;
- 列数据是大小写混合的,但报表程序需要把所有数据按大写表示出来
- 物品订单表存储物品的价格和数量,不存储每个物品的总价格
- 需要根据表数据进行诸如总数、平均数的计算。
计算字段是在运行时在SELECT语句内创建的。
拼接字段
拼接:将值联接到一起(将一个值附加到另一个值)构成单个值。
在SQL中的SELECT语句中,可使用一个特殊的操作符来拼接两个列,操作符可用加号(+)和(||)表示。
SELECT vend_name + ' (' + vend_country + ')'
FROM Vendors
ORDER BY vend_name;
使用函数处理数据
与sql语句不同,SQL函数不是可移植的。这意味着为特定SQL实现编写的代码在其他实现中可能不正常。
字符串函数(文本处理函数)
表中的SOUNDEX是一个将任何文本串转换为描述其语音表示的字母数字模式的算法
日期和时间处理函数
日期和时间采用相应的数据类型存储在表中,每种DBMS都有自己特有的形式。
应用程序一般不使用日期和时间的存储格式,因此日期和时间函数总是用来读取、统计和处理这些值。由此他很重要,但它们的可移植性最差。
数值处理函数
处理数值数据,这些函数一般用于代数、三角或几何运算。
聚集函数
我们经常需要汇总数据而不用把它们实际检索出来,为此 SQL 提供了专门的函数。这种类型的检索例子有:
- 确定表中行数;
- 获得表中某些行的和;
- 找出表列的最大值、最小值、平均值。
聚集函数:对某些运行的函数,计算并返回一个值。
-
AVG()函数
AVG()通过对表中行数计数并计算其列值之和,求得该列的平均值。
SELECT AVG(prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';
此WHERE 子句仅过滤出 vend_id 为 DLL01 的产品,因此 avg_price 中返回的值只是该供应商产品的平均值。
注意:AVG()函数只能用于单个列,而且列名必须作为函数参数给出。函数忽略值为NULL的行。
-
COUNT()函数
利用count()确定表中行的数目或符合特定条件的行的数目。
- 使用count(*)对表中行的数目进行计数,不管表列中包含的是空值还是非空值;
- 使用count(Column)对特定列中具有值的行进行计数,忽略NULL值。
SELECT COUNT(*) AS num_cust -- 返回 Customers 表中顾客的总数
FROM Customers;
SELECT COUNT(cust_email) AS num_cust -- 只对具有电子邮件地址的客户计数:
FROM Customers;
-
MAX()函数
返回指定列中的最大值。
SELECT MAX(prod_price) AS max_price
FROM Products;
在用于文本数据时,MAX()返回按该列排序后的最后一行。
-
MIN()返回最小值
-
SUM()函数
返回指定列值的和。
SELECT SUM(item_price*quantity) AS total_price FROM OrderItems WHERE order_num = 20005;
聚集不同值
- 对所有行执行计算,指定ALL参数或不指定参数;
- 只包含不同的值,指定DISTINCT参数。
SELECT AVG(DISTINCT prod_price) AS avg_price
FROM Products
WHERE vend_id = 'DLL01';
注意:DISTINCT不能用于COUNT(*)。
组合聚集函数
SELECT函数可根据需要包含多个聚集函数。
SELECT COUNT(*) AS num_items,
MIN(prod_price) AS price_min,
MAX(prod_price) AS price_max,
AVG(prod_price) AS price_avg
FROM Products;
分组函数
创建分组
分组使用GROUP BY的子句建立。
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
GROUP BY vend_id;
GROUP BY子句的一些重要规定:
- GROUP BY子句可以包含任意数目的列,因而可以对分组进行嵌套,更细致地进行数据分组;
- 如果在GROUP BY子句中嵌套了分组,数据将在最后指定的分组上进行汇总;
- GROUP BY子句中列出的每一列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。
- 大多数SQL实现不允许GROUP BY列带有长度可变的数据类型(如文本或备注型字段);
- 除聚集计算语句外,select语句中的每一列都必须在group by子句中给出;
- 如果分组列中包含具有 NULL 值的行,则 NULL 将作为一个分组返回。如果列中有多行 NULL 值,它们将分为一组。
- GROUP BY 子句必须出现在 WHERE 子句之后,ORDER BY 子句之前
过滤分组
过滤分组规定包括哪些分组,排除哪些分组。用having 来实现,目前学过的where子句都可以用having来替代,唯一差别是,where过滤行,having过滤分组。
SELECT cust_id, COUNT(*) AS orders
FROM Orders
GROUP BY cust_id
HAVING COUNT(*) >= 2;
有时需要在同一条语句中同时使用where和having:
SELECT vend_id, COUNT(*) AS num_prods
FROM Products
WHERE prod_price >= 4
GROUP BY vend_id
HAVING COUNT(*) >= 2;
分组和排序
SELECT order_num, COUNT(*) AS items
FROM OrderItems
GROUP BY order_num
HAVING COUNT(*) >= 3
ORDER BY items, order_num;
SELECT子句顺序
SQL代码规范
[SQL编程格式的优化建议] https://zhuanlan.zhihu.com/p/27466166
[SQL Style Guide] https://www.sqlstyle.guide/
作业
#作业#
项目一:查找重复的电子邮箱(难度:简单)
创建 email表,并插入如下三行数据
±—±--------+
| Id | c |
±—±--------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
±—±--------+
编写一个 SQL 查询,查找 Email 表中所有重复的电子邮箱。
根据以上输入,你的查询应返回以下结果:
±--------+
| Email |
±--------+
±--------+
说明:所有电子邮箱都是小写字母。
项目二:查找大国(难度:简单)
创建如下 World 表
±----------------±-----------±-----------±-------------±--------------+
| name | continent | area | population | gdp |
±----------------±-----------±-----------±-------------±--------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000 |
| Albania | Europe | 28748 | 2831741 | 12960000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000 |
| Andorra | Europe | 468 | 78115 | 3712000 |
| Angola | Africa | 1246700 | 20609294 | 100990000 |
±----------------±-----------±-----------±-------------±--------------+
如果一个国家的面积超过300万平方公里,或者(人口超过2500万并且gdp超过2000万),那么这
编写一个SQL查询,输出表中所有大国家的名称、人口和面积。
例如,根据上表,我们应该输出:
±-------------±------------±-------------+
| name | population | area |
±-------------±------------±-------------+
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
±-------------±------------±-------------+
项目一:
项目一
-- 创建表
CREATE TABLE email (
ID INT NOT NULL PRIMARY KEY,
Email VARCHAR(255)
);
-- 插入数据
INSERT INTO email VALUES('1','[email protected]');
INSERT INTO email VALUES('2','[email protected]');
INSERT INTO email VALUES('3','[email protected]');
项目二: