数据库基础
数据库≠数据库软件
确切的说,数据库软件应称为数据库管理系统(DBMS),数据库是通过DBMS创建和操作的容器
数据库相当于文件柜(容器),表相当于文件
同一个数据库不能存在相同的表名,不同的数据库可以存在相同的表名
主键应满足的条件:
- 唯一性
- 非空性(NOT NULL)
- 主键列中的值不允许修改或更新
- 主键值不能重用(某行从表中删除,其主键不能赋给新行)
注:可以一起使用多个列作为主键,所有列值的组合必须是唯一的,但其中单个列的值可以不唯一
检索数据
SQL语句一般返回原始的、无格式的数据,不同的DBMS和客户端显示数据的方式略有不同,数据的格式化是表示问题,而不是检索问题
select * from products;
一般而言,除非确实需要表中的每一列,否则最好别使用*
通配符,检索不需要的列通常会降低检索速度和应用程序的性能;当然,通配符也有一个大优点:可以检索出名字未知的列
select distinct vend_id, prod_price from products;
使用distinct检索不同的列值,注意distinct关键字作用于其后所有的列,不仅仅是跟在其后的一列,即取多个列组合起来的不同结果
当需要返回一定数量的行时,各种数据库的实现并不相同:
- SQL Server:
select top 5 prod_name from products;
- DB2:
select prod_name from products fetch first 5 rows only;
- Oracle:
select prod_name from products where rownum <=5;
- MySQL、SQLite等:
select prod_name from products limit 5;
当需要从指定位置开始检索一定数量的行数时,limit和offset组合使用
select prod_name from products limit 4 offset 3;
从第4行开始,检索4行数据(起始行为第0行);MySQL、MariaDB、SQLite中可以把limit 4 offset 3
简化为limit 3,4
,注意 ,
之前的值对应offset,,
之后的值对应limit(反过来了)
使用注释
- 行内注释
--文本
,可以嵌在行内,--之后的文本就是注释
#文本
,在一行的开始处使用#,这一整行都将作为注释
select prod_name from products; --这是一条注释
#这是一条注释
select prod_name from products;
- 多行注释
/*文本*/
,从/*
到*/
之间的所有内容都是注释
/*select prod_name ,
vend_id
from products; */
select prod_name from products;
排序检索
SQL语句由子句构成,有些子句是必需的,有些则是可选的。一个子句通常由一个关键字加上所提供的数据组成。例如select语句的from子句。
order by 子句:取一个或多个列的名字,据此对输出进行排序。
注意:在指定一条 order by 子句时,应该保证它是select语句中最后一条子句。如果它不是最后的子句,将会出错。
按列位置(相对位置)排序:
除了能用列名指出排序顺序外,order by 还支持按相对位置进行排序。
select prod_id, prod_price, prod_name
from Products
order by 2, 3;
order by 2 表示按select清单中的第二个列prod_price进行排序;order by 2, 3 表示先按prod_price,再按prod_name进行排序。
这一技术的主要好处在于不用重新输入列名;缺点是可能造成错用列名、对select清单进行更改时容易错误地对数据进行排序、如果进行排序的列不在select清单中,显然不能使用这项技术。
如果有必要,可以混合使用实际列名和相对列位置
指定排序方向
数据排序默认是升序排序(从A到Z),当然,也可以使用DESC关键字在order by 子句中进行降序排序
select prod_id, prod_price, prod_name
from Products
order by prod_price DESC, prod_name;
DESC关键字只应用到直接位于其前面的列名,因此,上面的语句prod_price列以降序排序,而prod_name列(在每个价格内)仍然以默认升序排序
注意:如果想在多个列上进行降序排列,必须对每一列指定DESC关键字
过滤数据
SQL过滤与应用过滤
SQL过滤之后,数据也可以在应用层过滤,但是通常这种做法及其不妥。优化数据库后可以更快速有效地对数据进行过滤。而让客户端应用(或开发语言)处理数据库的工作将会极大地影响应用的性能,并且使所创建的应用完全不具备可伸缩性。此外,如果在客户端过滤数据,服务器不得不通过网络发送多余的数据,这将导致网络带宽的浪费。
使用between关键字时,必须指定两个值--所需范围的低端值和高端值,这两个值必须用and关键字分隔。between匹配范围中的所有的值,包括指定的开始值和结束值,即左闭右闭[ ]区间。
确定值是否为NULL,不能简单地检查是否等于NULL,select语句有一个特殊的where子句,可用来检查具有NULL值的列,这个where子句就是 IS NULL 子句
select cust_name
from Customers
where cust_email IS NULL;
NULL和非匹配
通过过滤选择不包含指定值的所有列时,我们可能希望返回包含NULL值的行,但是这做不到,因为NULL比较特殊,所以在进行匹配过滤或非匹配过滤时,不会返回这些结果。
高级数据过滤
在where子句中使用圆括号
任何时候使用具有AND和OR操作符的where子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认求值顺序,即使它确实如你希望的那样。使用圆括号没有什么坏处,它能消除歧义。
IN操作符
where子句中用来指定要匹配的清单的关键字,功能与OR相当
其优点如下:
- 在有很多合法选项时,IN操作符的语法更清楚、更直观
- 在与其他AND和OR操作符组合使用IN时,求值顺序更容易管理
- IN操作符一般比一组OR操作符执行得更快
- IN操作符的最大优点是可以包含其他select语句,能够动态地建立where子句
NOT操作符
where子句中用来否定其后条件的关键字
select prod_name
from Products
where NOT vend_id = 'DLL01'
order by prod_name;
上面的例子也可以使用 <> 操作符来完成
select prod_name
from Products
where vend_id <> 'DLL01'
order by prod_name;
为什么使用NOT?
对于简单的where子句,使用NOT确实没有什么优势,但在更复杂的子句中,NOT是非常有用的。例如,在与IN操作符联合使用时,NOT可以非常简单地找出与条件列表不匹配的行
用通配符进行过滤
通配符本身实际上是SQL的where子句中有特殊含义的字符,SQL支持几种通配符。为在搜索子句中使用通配符,必须使用LIKE操作符。LIKE指示DBMS,后跟的搜索模式利用通配符匹配而不是简单的相等匹配进行比较。
最常使用的通配符是百分号(%),表示任何字符出现任意次数(0次、1次或多次)。
select prod_id, prod_name
from Products
where prod_name like 'Fish%';
此例子使用了搜索模式 'Fish%' ,将检索任意以Fish起头的词,%告诉DBMS接受Fish之后的任意字符,不管它有多少字符
MySQL等DBMS默认搜索是不区分大小写的,根据DBMS的不同及其配置,搜索是可以区分大小写的。如果区分大小写,则 'fish%' 与 Fish bean bag toy就不匹配
注意NULL:通配符%看起来像是可以匹配任何东西,但有个例外,这就是NULL。子句 where prod_name like '%'
不会匹配产品名称为NULL的行
另一个有用的通配符是下划线(_),它只匹配单个字符,而不是多个字符。
select prod_id, prod_name
from Products
where prod_name like '__ inch teddy bear';
注意这个where子句中的搜索模式给出了后面跟有文本的两个通配符,结果如下:
8 inch teddy bear 产品没有匹配,因为搜索模式要求匹配两个通配符而不是一个,%通配符则可以有任意多个。
与 % 能匹配任意个数的字符不同,_ 总是刚好匹配一个字符,不能多也不能少。
使用通配符的技巧:
正如所见,SQL的通配符很有用,但这种功能是有代价的,即通配符搜索一般比前面讨论的其他搜索要耗费更长的处理时间,这里给出一些使用通配符时要记住的技巧:
- 不要过度使用通配符。如果其他操作符能达到相同的目的,应该使用其他操作符
- 在确实需要使用通配符时,也尽量不要把它们用在搜索模式的开始处。把通配符置于开始处,搜索起来是最慢的
- 仔细注意通配符的位置。如果放错地方,可能不会返回想要的数据