数据库知识梳理
这段时间刚好在做数据库方面工作,重新阅读了《SQL必知必会》(第五版),梳理了下数据库相关的知识,我不是专业的数据库管理人员,仅站在这本书的读者角度进行总结
这本书算是不错的sql入门级教材,有讲解案例,有总结作业,跟着敲一遍也会有收获,更重要它的分节很有意思,定义为10分钟一节,一共22小节,就算零基础跟着学完也不会花太多时间
正式开始之前,请大家安装好mysql环境(其他数据库请自行安装)
MySQL安装教程(windows):
- http://t.csdnimg.cn/84EMH
navicat下载链接(直接官网下载安装即可):
- https://www.navicat.com/en/download/navicat-premium
学习资源(电子书+脚本等):
- 链接:https://pan.baidu.com/s/1QdCmmfVgHrNwcCizePx4Rg?pwd=mzxg
- 提取码:mzxg
一、准备工作
1、阅读附录A:先熟悉样例表结构
2、创建数据库
3、创建样例表:新建查询,将txt文件复制进去并执行,然后刷新表(如果报错,请注意脚本的第一行和第五行,将它注释掉)
4、现在环境准备OK,接下来正式开始
二、基础语法
1、结束符:“;”
2、多行注释:“/* */”
3、单行注释:“-- ”,注意末尾有空格
4、行内注释:“# ”
5、大小写不敏感
三、简单查询
1、基本格式:select A from B;
格式:select 列名 from 表名;
- 示例:select * from customers;
- 说明:*表示字段通配符,上面表示查询 customers 表的所有字段
- 示例:select cust_id from orders;
- 说明:上面表示查询 orders 表的 cust_id 字段
- 示例:SELECT cust_id, order_date FROM orders;
- 说明:上面表示查询 orders 表的 多个 字段
2、指定行:limit
格式:select 列名 from 表名 limit 下标,行数;
- 示例:select * from orders limit 1, 2;
- 说明:上面表示查询 orders 表,从下标为1(第二行)开始,共返回2行
- 示例:select * from orders limit 3;
- 说明:上面表示查询 orders 表,从下标为0(第一行)开始,共返回3行
3、排序:order by
格式:select 列名 from 表名 order by 列名 排序规则;
- 示例:select * from customers order by cust_name;
- 说明:上面表示查询 customers 表,查询结果按 cust_name 升序排序;
- 示例:select * from customers order by cust_name desc;
- 说明:上面表示查询 customers 表,查询结果按 cust_name 降序排序;
- 示例:select * from products order by prod_price, prod_id DESC;
- 说明:上面表示查询 products 表,查询结果先按 prod_price升序,再按 prod_id 降序;
4、指定行+排序
- 示例:select * from products order by prod_price limit 1;
- 说明:查询最便宜的产品
5、去重:distinct
格式:select distinct 列名 from 表;
- 示例:select DISTINCT cust_id from orders;
- 说明:查询 orders 表的顾客ID,单列去重
- 示例:select DISTINCT cust_id, order_num from orders;
- 说明:查询 orders 表的顾客ID,多列去重(保证每行不重复,可以行中某些列重复)
补充:
多种子句组合是实际使用中最常用的方式,这里就会涉及不同子句间的位置问题。
- select子句一般顺序:
- 1、列名或表达式
- 2、from 子句
- 3、join 子句(联结)
- 4、where子句(过滤)
- 5、group by子句(分组)
- 6、having 子句(分组后过滤)
- 7、order by(排序)
- 8、limit(指定行)
以上就是 “简单查询” 需要了解的知识,下面学习——条件查询
四、条件查询
1、基本格式:select A from B where C;
2、比较运算:
等于:=
不等于: !=
小于:<
小于等于:<=
大于:>
大于等于:>=
- 示例:SELECT * from vendors WHERE vend_id = ‘bre02’;
- 说明:查询 vendors 表,筛选 vend_id 为 bre02 的记录,注意字符串类型要用引号包裹
空:is null
非空:is not null
- 示例:SELECT * from customers WHERE cust_email != ‘sales@villagetoys.com’;
- 说明:查询 customers 表,筛选 cust_email 不是上述值的记录,注意查询结果不包含NULL
3、逻辑运算
或者:or
并且:and
非:not
- 示例:SELECT * from customers WHERE cust_email != ‘sales@villagetoys.com’ or cust_email is null;
- 说明:查询 customers 表,筛选 cust_email 不是上述值 或者 cust_email值为空 的记录
- 示例:SELECT * from vendors WHERE not vend_id = ‘bre02’;
- 说明:查询 vendors 表,筛选 vend_id 不为 bre02 的记录
4、范围匹配
在A和B之间:between A and B
在某个集合之中:in (A, B, C)
- 示例:SELECT * from orders WHERE order_date BETWEEN ‘2020-01-12 00:00:00’ and ‘2020-02-03 00:00:00’;
- 说明:查询 orders 表,筛选 order_date 在上述值之间的记录,注意日期用引号包裹,前者应该比后者小
- 示例:select * from orders WHERE order_num in (20005, 20007);
- 说明:查询 orders 表,筛选 order_num 为上述值得记录
5、模糊匹配
匹配任意个任意字符:%
匹配单个任意字符:_
- 示例:select * from customers WHERE cust_name like ‘%o%’;
- 说明:查询 customers 表,筛选 cust_name 包含 ‘o’ 的记录
- 示例:select * from customers WHERE cust_name like ‘_illage Toys’;
- 说明:查询 customers 表,筛选 cust_name 以任意字符开头,illage Toys 结尾的记录
补充:
1、如果使用 and 或者 or 多个逻辑运算符时,推荐加上(),因为and优先级更高
2、如果使用 in 操作符和 or 操作符都可以实现某筛选,推荐使用 in,因为:
- in 语法更清晰
- in 性能更好
- in 可以包含其他where子句(子查询)
以上就是 “条件查询” 需要了解的知识,下面学习——字段处理
五、字段处理
1、给字段起别名
关键字:as 或者 空格键
- 示例:select order_num as ‘订单号’ from orders;
- 说明:查询 customers 表的 order_num 字段,字段名显示为 “订单号”
- 提示:后续学习联结表时,也会使用as关键字
2、字段的四则运算
关键字:+ - * /
- 示例:SELECT order_num ‘订单号’, prod_id ‘产品编号’, quantity*item_price as ‘各订单每种产品总金额’ from orderitems;
- 说明:查询 orderitems 表,每个订单中,各种产品的总金额
3、字符按的处理函数——聚合函数
关键字:max(), min(), avg(), count(), sum() ——计算最大值、最小值、平均值、数量、和
- 示例:SELECT MAX(order_num) ‘最大订单号’, MIN(item_price) ‘最低产品价格’, avg(item_price) ‘平均产品价格’, SUM(quantity) ‘产品总数’, COUNT(*) ‘总记录数’ from orderitems;
- 说明:查询orderitems表的各种信息
- 示例:SELECT AVG(DISTINCT order_num) from orderitems;
- 说明:查询 orderitems 表,先对 order_num 字段进行去重,然后计算平均值
4、字段的处理函数——字符串
关键字:trim(), rtrim(), ltrim() ——去除字符串两端/右边/左边的空格
关键字:concat() ——拼接多个字符串
关键字:upper(), lower() ——将字符串转为大写/小写
关键字:length() ——返回字符串长度
关键字:left(), right() ——返回指定数量的字符串,从左/右开始
关键字:substr() ——提取指定位置,指定长度的字符串
- 示例:SELECT TRIM(cust_name) from customers;
- 说明:查询 customers 的 cust_name字段,剔除左右两端的空格
- 示例:SELECT CONCAT(‘hi~’,cust_name), lower(cust_name), length(cust_name), left(cust_name, 2), SUBSTR(cust_name, 2, 3) from customers;
5、字段的处理函数——日期
关键字:DATE_FORMAT() ——格式化输入日期
关键字:year(), month(), day() ——提取日期的年、月、日
- 示例:SELECT DATE_FORMAT(order_date, ‘%Y-%m-%d’), YEAR(order_date) from orders;
- 说明:查询 orders 表的订单日期,以 年-月-日 格式输出,提取年份
6、字段的处理函数——数值
关键字:sin(), cos(), tan() ——计算对应值的正弦/余弦/正切
关键字:exp(), sqrt(), pow() ——计算e的N次方,计算平方根,计算次方
关键字:abs(), pi() ——返回绝对值,返回Π(派)
- 示例:SELECT sin(order_num), PI(), pow(order_item, 2), EXP(order_item),
SQRT(order_item), POW(order_item,2) from orderitems order by order_item; - 说明:查询 orderitems 表 的各个字段,并进行计算
以上就是 “字段处理” 需要了解的知识,下面学习——分组查询
六、分组查询
1、基本格式:select A from B where C group by D;
注意:group by子句有规则限制
1、每个 SELECT 语句中的列要么在 GROUP BY 子句中,要么是聚合函数的参数
2、如果 GROUP BY 子句中包含多个列,结果将按照这些列的组合进行分组
3、使用 GROUP BY 子句时,NULL 值将被分成一组
4、如果某个列是表达式并起了别名,如果用该列分组,不能使用别名,只能写表达式(跟具体DBMS和版本有关)
在实际使用中,group by 子句通常会结合 聚合函数使用,因为执行过程中,会先进行分组,然后对分组的数据进行聚合运算
2、只分组,不进行聚合
- 示例:select order_num from orderitems GROUP BY order_num;
- 说明:查询 orderitems 表的 order_num 字段,结果按 order_num 分组;
- 提示:如果只进行分组,而不进行聚合,查询结果可能和“去重”的查询结果一致
3、分组聚合
- 示例:select order_num, count(*) ‘订单产品数’, max(quantity) from orderitems GROUP BY order_num;
- 说明:查询 orderitems 表,按照订单号进行分组,统计每个组的数量,最大购买产品数
4、多个字段组合分组
- 示例:select order_num from orderitems GROUP BY order_num, order_item;
- 说明:查询 orderitems 表,按照 order_num 和 order_item 字段组合进行分组(只要组合起来不重复,就可以分为一组)
5、having过滤分组结果
- 示例:select order_num from orderitems GROUP BY order_num HAVING order_num >= 20007;
- 说明:查询 orderitems 表,按照 order_num 分组,筛选结果中 order_num >= 20007 的记录
6、目前我们除了join子句,都已经见过了,现在看下组合使用
基本格式:select 列 from 表 where 表过滤条件 group by 分组条件 having 分组后结果过滤条件 order by 排序规则 limit 指定行数;
复习子句顺序:列名(表达式) 》 from子句 》 join(子句) 》 where子句 》 group by子句 》 having子句 》 order by子句 》 limit子句
注意:有一点需要注意,having过滤是对分组并处理后的结果进行过滤,也就是如果分组后有聚合操作等,先进行聚合运算,再进行having过滤
以上就是 “字段处理” 需要了解的知识,下面学习——子查询
七、子查询
1、利用子查询结果作为过滤条件
- 示例:SELECT * from orderitems WHERE order_num in (SELECT order_num from orders WHERE order_date > ‘2020-01-30 00:00:00’);
- 说明:查询 orders 表的 order_num 字段作为 orderitems 表的查询条件
- 注意:作为过滤条件只能查询单个列,实际工作中不建议嵌套太多子查询
2、利用子查询结果作为字段
- 示例:SELECT cust_name, (select count(*) from orders WHERE orders.cust_id = customers.cust_id) as ‘下单数量’ from customers order by cust_name;
- 说明:查询 customers 表的 cust_name字段,新增一列子查询字段表示每位客户的下单数量
- 注意:如果字段有歧义时,例如下面的cust_id,需要确定具体的表
以上就是 “字段处理” 需要了解的知识,下面学习——连接表
八、连接表
注意:连接表,如果不写过滤条件或者联结条件,返回的结果将是笛卡尔积形式,应为每个表的每个字段都会和另一张表的每个字段进行匹配
1、等值连接
根据两张表相关键(外键)进行匹配查询
- 示例:SELECT vend_name, prod_name, prod_price FROM Vendors, Products WHERE Vendors.vend_id = Products.vend_id;
- 说明:根据供应商ID联结供应商表和产品表, 查询部分供应商及产品信息
- 注意:只返回两个表的vend_id相等的记录
2、内连接
根据两张表相关键(外键)进行匹配查询
查看下面的例子,不难发现其实内联结可以实现上述等值联结的功能,
- 示例:select c.cust_id, c.cust_name, o.order_num from customers c INNER JOIN orders as o on c.cust_id = o.cust_id;
- 说明:根据客户ID联结客户商表和订单表, 查询部分客户及订单信息
- 注意:只返回两个表的cust_id相等的记录
3、自连接
根据某个字段,联结自身表
样例表没有例子,这里给出一个简单SQL解释
查看下面的例子不难发现,其实子查询也可以实现自联结的功能,实际工作中推荐自联结,通常效率更高
4、外连接
根据两张表相关键(外键)进行匹配查询
我们刚刚使用内联结查询了 客户表和订单表,只有两张表的cust_id相匹配时才会返回
如果使用左联结,即使左边表的cust_id字段,找不到与之匹配的右边表的cust_id字段,仍然会返回这行记录
下面以左联结为例
- 示例:select c.cust_id, o.order_num, o.order_date from customers c left JOIN orders as o on c.cust_id = o.cust_id;
- 说明:用cust_id字段关联两张表,保留左表的全部行去匹配右表的行,能匹配则匹配,不能匹配则为NULL
5、自然连接
自然联结特性:根据表的列名自动匹配连接对应列,不需要使用关键字on, 自动去重重复列
了解即可,实际工作中,两张连接表的列名一般不同,所以还是需要使用 on 来连接指定字段
- 示例:SELECT customers.*, order_num FROM Customers JOIN Orders USING (cust_id) JOIN OrderItems USING(order_num) WHERE prod_id = ‘RGAN01’;
- 说明:查询三张表,通过相同列名进行自然连接
以上就是 “连接表” 需要了解的知识,下面学习——UNION查询
九、UNION查询
注意:union不是将表的结果连接起来,而是作为同一个字段进行整合
规则:
1、union可以多次查询同一张表
2、union可以查询不同的表(重点)
3、UNION 中的每个查询必须包含相同的列、表达式或聚集函数(列数一致,顺序不管),返回结果的列名以第一个查询的列名为准
4、默认情况下,UNION操作会去除重复的行,如果需要重复行,请使用 union all
5、order by 和 limit 只能写在最后一个查询中,对整个结果进行处理,而不是对每个查询分别处理
- 示例:SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN (‘IL’,‘IN’,‘MI’)
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = ‘Fun4All’;
你可能会发现,上述示例,其实用一条select语句+or连接两个过滤条件就能实现,那么使用union的场景在哪里呢?
1、合并多个数据源的结果集(查询不同表的类似列,试想下,如果上面的例子是查询不同表的不同过滤条件,还适合能or进行连接吗?)
2、去重: UNION 会自动去除重复的行
3、按特定顺序返回结果:union支持对结果进行排序
以上就是 “UNION查询” 需要了解的知识,下面学习——插入数据
十、插入数据
执行插入操作能否成功,还要看是否满足约束条件,后面写约束时补充
1、插入所有字段:insert into 表名 values(值);
- 示例:INSERT INTO customers VALUES(1000000006, ‘Toy Land’, ‘123 Any Street’, ‘New York’, ‘NY’, ‘11111’, ‘USA’, NULL, NULL);
- 说明:按表字段顺序,依次插入值,每次插入一行
2、插入指定字段:insert into 表名(列名) values(值);
- 示例:INSERT INTO Customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(1000000006, ‘Toy Land’, ‘123 Any Street’, ‘New York’, ‘NY’, ‘11111’, ‘USA’, NULL, NULL)
- 说明:按列出的字段顺序,一次插入值,每次插入一行
3、插入查询结果(复制表):insert into 表名(列名) select 列名 from 表名;
注意:
1、插入的行数取决于查询结果的行数
2、select的列名不需要和insert的列名一样,只要顺序相同即可
- 示例:INSERT INTO Customers(cust_id, cust_contact, cust_email, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country) SELECT cust_id, cust_contact, cust_email, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country FROM CustNew;
- 说明:可以把一个表的数据复制到另一张表
以上就是 “插入数据” 需要了解的知识,下面学习——更新和删除数据
十一、更新和删除数据
1、更新数据,基本格式:update 表名 set 字段=值, 字段2=值2 where 过滤条件;
注意:如果不写where过滤条件,将会对所有行的对应字段进行更新
- 示例:UPDATE Customers SET cust_contact = ‘Sam Roberts’, cust_email = ‘sam@toyland.com’ WHERE cust_id = 1000000006;
2、删除数据,基本格式:delete from 表名 where 过滤条件;
注意:如果不写where过滤条件,将会对所有行的数据进行删除
- 示例:DELETE FROM Customers WHERE cust_id = 1000000006;
3、删除数据方式对比
delete from 表名:逐行删除,保留表结构和元数据(删除速度较慢)
truncate table 表名:整表删除,保留表结构和元数据(删除速度较快,不触发触发器,不记录删除行,自动提交事务,不支持回滚)
drop table 表名:整表删除,不保留任何数据(删除速度最快,不可逆,自动提交事务,不支持回滚)
以上就是 “更新和删除数据” 需要了解的知识,下面学习——创建和操纵表
十二、创建和操纵表
1、约束
约束类型:
主键:PRIMARY KEY ——不为空,不重复,不重用,不修改
外键:FOREIGN KEY ——关联另一张表的主键
非空:NOT NULL ——不为空
默认:DEFAULT ——插入时未提供值,自动填充默认值
唯一:UNIQUE ——不重复
检查:CHECK ——检查值满足特定条件
自增:AUTO_INCREMENT ——插入新行时,自动分配一个唯一值,需要数据类型为数值型,常用于主键列
索引:INDEX ——用于提高搜索性能,一个表中可以有多个列有索引,但是会降低增、删、改的性能,表中索引名要唯一,创建索引会占用存储空间
2、创建表
基本格式:create table 表名(字段名 类型 约束, 字段名2 类型2 约束2, CONSTRAINT 字段名 约束)
- 示例:CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
password VARCHAR(100) NOT NULL,
registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
role_id int,
INDEX idx_username(username),
CONSTRAINT fk_role_id FOREIGN KEY (role_id) REFERENCES roles(id),
CONSTRAINT email_format CHECK (email LIKE ‘%@%.%’)
);
3、创建表:使用select(只有表结构和数据,没有元数据)
基本格式:create table 表名 as select 列名 from 表名2;
- 示例:CREATE TABLE new_table_name AS
SELECT column1, column2, …
FROM source_table_name
WHERE condition;
4、删除表:
基本格式:drop table 表名;
5、更新表:
基本格式:alter table 表名 操作1, 操作2;
- 示例:ALTER TABLE Vendors ADD 列名 数据类型 约束;
- 说明:新增列
- 示例:ALTER TABLE Vendors DROP COLUMN 字段名;
- 说明:删除列
- 示例:ALTER TABLE table_name ADD PRIMARY KEY (主键字段名);
- 说明:增加主键
- 示例:ALTER TABLE table_name DROP PRIMARY KEY;
- 说明:删除主键
- 示例:ALTER TABLE table_name ADD CONSTRAINT 外键名 FOREIGN KEY (字段名) REFERENCES 关联表(关联主键名);
- 说明:添加外键
- 示例:ALTER TABLE table_name DROP FOREIGN KEY 外键名;
- 说明:删除外键
- 示例:ALTER TABLE table_name CHANGE COLUMN 列名 新列名 数据类型 约束;
- 说明:重命名列
- 示例:重命名表
- 说明:ALTER TABLE 表名 RENAME TO 新表名;
以上就是 “创建和操纵表” 需要了解的知识,下面学习——视图
十三、视图
1、创建视图
基本格式:create view 视图名 as select 列名 from 表名;
说明:
1、视图是一张虚拟的表,存放查询的数据
2、查询视图时,如果基础表的数据发生了变化,视图会返回最新的结果(视图本质上是一个查询)
3、创建视图时,通常不使用order by 语句(使用时可以用)
- 示例:CREATE VIEW CustomersWithOrders as
SELECT Customers.* FROM customers
RIGHT JOIN orders on customers.cust_id = orders.cust_id; - 说明:创建一个视图,包含仅下过单的客户数据
2、删除视图
基本格式:drop view 视图名;
以上就是 “视图” 需要了解的知识,下面学习——存储过程
十四、存储过程
1、创建存储过程
基本格式:
DELIMITER //
CREATE PROCEDURE 过程名(in 输入参数名,out输出参数名)
BEGIN
declear 变量名 类型;
select 列名 into 变量名 from 表名;
set 输出参数名 = 变量名;
select 输出参数名;
END //
DELIMITER ;
说明:
1、存储过程是一组预编译的 SQL 语句和逻辑操作,常用于封装一系列常见的数据库操作
-
示例:DELIMITER //
CREATE PROCEDURE NewOrder (IN cust_id char(10), OUT new_order_num INT)
BEGIN
declare max_order_num int;
SELECT MAX(order_num) into max_order_num
from orders;
SET new_order_num = IFNULL(max_order_num,0) + 1;INSERT into orders(order_num, order_date, cust_id)
VALUES(new_order_num, CURDATE(), cust_id);select new_order_num;
END //
DELIMITER ;
2、执行存储过程
基本格式:CALL 存储过程名(入参名, @出参名);
- 示例:CALL NewOrder(‘1000000006’, @new_order_num);
以上就是 “存储过程” 需要了解的知识,下面学习——事务
十五、事务
1、创建事务
基本格式:
DELIMITER //
START TRANSACTION;
SQL语句1;
SAVEPOINT 保留点名;
SQL语句2;
ROLLBACK TO 保留点名;
SQL语句3; # 回滚到保留点后,这条语句仍会执行
ROLLBACK;
COMMIT;
DELIMITER ;
说明:
1、事务是一组sql语句,要么全部执行成功,要么全部执行失败并回滚到指定保留点
2、DDL(数据定义语言)语句会自动提交,无法回退(例如:create、alter、drop语句)
以上就是 “事务” 需要了解的知识,下面学习——游标
十六、游标
1、创建游标
基本格式:
DELIMITER //
CREATE PROCEDURE fetch_users()
BEGIN
DECLARE user_id INT;
DECLARE username VARCHAR(50);
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE user_cursor CURSOR FOR
SELECT user_id, username FROM users;
OPEN user_cursor;
FETCH user_cursor INTO user_id, username;
WHILE NOT done DO
FETCH user_cursor INTO user_id, username;
if not found then
set done := True;
else
SELECT CONCAT('User ID: ', user_id, ', Username: ', username);
end if;
END WHILE;
CLOSE user_cursor;
END//
DELIMITER ;
说明:
1、游标是一个存储在 DBMS 服务器上的数据库查询
2、声明游标时需指定sql语句
3、游标提供了一种灵活的机制来处理查询结果集,特别适用于需要逐行处理数据或分批处理数据的情况
以上就是 “游标” 需要了解的知识,下面学习——触发器
十七、触发器
1、创建触发器
基本格式:
DELIMITER //
CREATE TRIGGER customer_state1
before INSERT ON Customers
FOR EACH ROW
BEGIN
SET NEW.cust_state = UPPER(NEW.cust_state);
END //
DELIMITER ;
- 点击执行后,查询触发器是否开启:SHOW TRIGGERS;
- 执行对应语句,看触发器是否正常工作
2、删除触发器
提示:触发器不能停止,只能删除()
- 示例:DROP TRIGGER IF EXISTS customer_state1 ;
以上就是 “触发器” 需要了解的知识,下面学习——数据类型
十八、数据类型
1、数值类型
整数:tinyint,smallint,mediumint,int, bigint
浮点数:float,double
定点数:decimal(M, D)
2、日期类型
year: YYYY
date: YYYY-MM-DD
time: HH:MM:SS
datetime: YYYY-MM-DD hh:mm:ss
timestamp: YYYY-MM-DD hh:mm:ss
3、字符串类型
普通字符串:char
不定长字符串:varchar
二进制:tinyblob,blob,mediumblob,longblob
文本:tinytext,text,mediumtext,longtext
4、其他类型
枚举:enum
集合:set
空间类型:GEOMETRY, POINT, LINESTRING, POLYGON...用于存储空间数据(地理信息、几何图形等)