四、SQL与关系数据库基本操作

1. SQL概述

  1. 结构化查询语言(Structured Query Language,SQL)是专门用来与数据库通信的语言,它可以帮助用户操作关系数据库。
  2. SQL的特点:
    1. SQL不是某个特定数据库供应商专有的语言
    2. SQL简单易学
    3. SQL强大、灵活,可以进行非常复杂和高级的数据库操作
  3. SQL的组成
    1. 数据查询
    2. 数据定义语言(Data Definition Language, DDL)
      1. CREATE:创建数据库或数据库对象
      2. ALTER:对数据库或数据库对象进行修改
      3. DROP:删除数据库或数据库对象
    3. 数据操纵语言(Data Manipulation Language, DML)
      1. SELECT:从表或视图中检索数据
      2. INSERT:将数据插入到表或视图中
      3. UPDATE:修改表或视图中的数据
      4. DELETE:从表或视图中删除数据
    4. 数据控制语言(Data Control Language, DCL)
      1. GRANT:用于授予权限
      2. REVOKE:用于收回权限
    5. 嵌入式和动态SQL规则:嵌入式和动态SQL规则规定了SQL语句在高级语言程序设计中使用的规范方法,以便适应较为复杂的应用。
    6. SQL调用和会话规则:以便提高SQL的灵活性、有效性、共享性以及SQL具有更多的高级语言特征。
      1. SQL例程
      2. 调用规则

2. MySQL预备知识

  1. SQL使用基础
    1. 关系数据库管理系统(RDBMS):优点是体积小、速度快、开放源代码、遵循GPL
    2. 构架方式
      1. LAMP:Linux、Apache、MySQL、PHP/Perl/Python
      2. WAMP:Windows、Apache、MySQL、PHP/Perl/Python
  2. MySQL扩展语言要素
    1. 常量:也称字面值或标量值

      1. 字符串常量
      2. 数值常量
      3. 十六进制常量
      4. 时间日期常量
      5. 位字段值
      6. 布尔值
      7. NULL值
    2. 变量

      1. 用户变量:用户变量前常添加一个符号@,用于将其与列名区分开
      2. 系统变量:大多数系统变量应用于其他SQL语句中时,必须在系统变量前添加两个@
    3. 运算符

      分类 运算符
      算术运算符 +、-、*、/、%
      位运算符 &、|、^、~、<<、>>
      比较运算符 =、 >、 <、 >=、 <=、 <>(不等于)、 !=、 <=>(相等或都等于空)
      逻辑运算符 NOT或!、AND或&&、OR或||、XOR(逻辑异或)
    4. 表达式:是常量、变量、列名、复杂计算、运算符和函数的组合

    5. 内置函数

      函数
      数学函数 ABS()
      聚合函数 COUNT()
      字符串函数 ASCⅡ()
      日期和时间函数 NOW()
      加密函数 ENCODE()
      控制流程函数 IF()
      格式化函数 FORMAT()
      类型转换函数 CAST()
      系统信息函数 USER()

3. 数据定义

1.数据库模式定义

  1. 创建数据库:使用CREATE DATABASECREATE SCHEMAS

    CREATE {DATABASE | SCHEMAS} [IF NOT EXISTS] db_name
    [DEFAULT] CHARACTER SET [=] charset_name
    [DEFAULT] COLLATE [=] collation_name
    
    //例
    create database if not exists db_name;
    
  2. 设置默认值:使用DEFAULT

    default character set charset_name;
    default collate collation_name;
    
  3. 查看数据库:使用SHOW DATABASESSHOW SCHEMA

    show databases db_name;
    show databases like '_name'; // LIKE关键字用于匹配指定的数据库名称
    show databases where expr; // WHERE从句用于指定数据库名称查询范围的条件
    
  4. 选择数据库:使用USE,从一个数据库“跳转”到另一个数据库

    use db_name;
    
  5. 修改数据库:ALTER DATABASE

    alter database db_name
    default character set gb2312
    default collate gb2312_chinese_ci;
    
  6. 删除数据库:DROP

    drop database if exists db_name;
    

2.表定义

  1. 创建表:

    1. 数据表是关系数据库中最重要、最基本的数据对象,也是数据存储的基本单位。
    2. 数据表被定义为字段的集合,按的格式来存储,每一代表一条记录,每一代表记录中一个字段的取值。
    create table table_name
    (
    字段名 数据类型 [列级完整性约束条件] [默认值],
    字段名N 数据类型 [列级完整性约束条件] [默认值],
    )[engint = 引擎类型];
    
    数据类型
    整型 int
    浮点型 double
    布尔型 bool
    日期型 date
    时间戳 timestamp
    时间型 time
    定长字符类型 char
    可变长字符 varchar

    示例:

    mysql> use mysql_test
    Database changed
    // create temporary table:则为临时表
    mysql> create table customers
        -> (
        -> c_id int not null auto_increment, // auto_increment:为当前列设置自增属性
        -> c_name char(50) not null,
        -> c_sex char(1) not null default 0, // default:设置默认值
        -> c_address char(50) null, // null:可为空
        -> c_contact char(50) null,
        -> primary key(c_id) // primary key():指定主键
        -> );
    Query OK, 0 rows affected (0.06 sec)
    
  2. 更新表

    使用ALTER TABLE语句,增加或删减列、创建或取消索引、更改原有列的数据类型、重新命名列或表、更改表的评注和表的引擎类型、为表重新创建触发器、存储过程、索引和外检等。

    1. ADD [COLUMN]子句

      向数据库mysql_test的表customers中添加一列,并命名为c_city,要求不能为NULL,默认字符串wuhan,且该列位于原表c_sex之后。

      mysql> alter table mysql_test.customers
          -> add column c_city char(10) not null default 'wuhan' after c_sex;
      
    2. CHANGE [COLUMN]子句:修改表中列的名称或数据类型

      mysql> alter table mysql_test.customers
          -> change column c_sex sex char(1) not null default "m";
      
    3. ALTER [COLUMN]子句:修改或删除表中列的默认值

      mysql> alter table mysql_test.customers
          -> alter column c_city set default 'beijing';
      
    4. MODIFY [COLUMN]子句:只修改指定列的数据类型,不会干涉它的列名。

      mysql> alter table mysql_test.customers
          -> modify column c_name char(20) first;
      
    5. DROP [COLUMN]子句:删除表中多余的列

      mysql> alter table mysql_test.customers
          -> drop column c_contact;
      
    6. RENAME [TO]子句:为表重新赋予一个表名

      mysql> alter table mysql_test.customers
          -> rename to mysql_test.backup_customers;
      // 或
      mysql> rename table mysql_test.backup_customers to mysql_test.customers;
      
  3. 删除表

    drop table if exists mysql_test.table_name;
    
  4. 查看表

    mysql> show columns from customers in mysql_test;
    // 或
    mysql> describe mysql_test.customers;
    // 或
    mysql> desc mysql_test.customers;
    

3.索引定义

  • 索引是提高数据文件访问效率的有效方法
  • 索引存在的弊端:
    • 索引是以文件的形式存储的,如果有大量的索引,索引文件可能比数据文件更快达到最大的文件尺寸。
    • 索引在提高查询速度的同时,会降低更新表的速度。
  • 分类:索引通常被创建成单列索引和组合索引
    • 普通索引(INDEX 或 KEY)
    • 唯一性索引(UNIQUE)
    • 主键(PRIMARY KEY)
  1. 索引的创建:

    使用CREATE INDEX语句创建

    在数据库mysql_test的表customers上,根据客户姓名前三个字符创建一个升序普通索引index_customers

    mysql> create index index_customers
        -> on mysql_test.customers(c_name(3) ASC);
    

    在数据库mysql_test的表customers上,根据客户id和姓名创建一个组合索引index_cust

    mysql> create index index_cust
        -> on mysql_test.customers(c_id, c_name);
    

    使用CREATE TABLE语句创建:

    创建表的同时创建该表的主键:

    mysql> create table customers
        -> (
        -> c_id int not null auto_increment,
        -> primary key(c_id)
        -> );
    

    创建表的同时创建该表的索引:

    mysql> create table customers
        -> (
        -> c_name char(50) not null,
        ->index index_name(c_name)
        -> );
    

    创建表的同时创建该表的唯一性索引:

    mysql> create table customers
        -> (
        -> c_sex char(1) not null default 0,
        -> unique index index_sex(c_sex) 
        -> );
    

    创建表的同时创建该表的外键:

    mysql> create table customers
        -> (
        -> c_address char(50) null, 
        -> foreign key index_address(c_address) 
        -> );
    

    在已有数据库mysql_test上新建一个包含产品卖家id号,姓名、地址、联系方式、售卖产品类型、销售量等内容的卖家信息表sellers,在建表的同时,为该表添加由卖家id号和产品类型组成的联合主键,并在销售量上创建索引。

    mysql> create table sellers
        -> (
        -> s_id int not null auto_increment,
        -> s_name char(20) not null,
        -> s_address char(50) null,
        -> s_contact char(20) null,
        -> s_product_type int(5) not null,
        -> s_sales int null,
        -> primary key(s_id, s_product_type),
        -> index index_sales(s_sales)
        -> );
    Query OK, 0 rows affected (0.02 sec)
    

    使用ALTER TABLE语句创建

    修改表的同时为该表添加索引:

    mysql> alter table mysql_test.sellers
        -> add index index_contact(s_contact);
    

    修改表的同时为该表添加主键:

    mysql> alter table temp
        -> add primary key(t_id);
    

    修改表时为该表添加唯一性索引:

    mysql> alter table mysql_test.sellers
        -> add unique index index_address(s_address);
    

    修改表时为该表添加外键:

    mysql> alter table temp
        -> add foreign key(s_id) references sellers(s_id);
    
  2. 索引的查看:使用SHOW INDEX语句

    show index from sellers in mysql_test;
    
  3. 索引的删除:

    使用DROP INDEX [ON]

    drop index index_contact on mysql_test.sellers;
    

    使用ALTER TABLE语句

    选用DROP PRIMARY KEY子句用于删除表中的主键,由于一个表中只有一个主键,其也是一个索引:

    mysql> alter table mysql_test.temp
        -> drop primary key;
    

    选用DROP INDEX子句删除各种类型的索引:

    mysql> alter table mysql_test.sellers
        -> drop index index_address;
    

    选用DROP FOREIGN KEY子句用于删除外键:

    mysql> alter table mysql_test.temp
        -> drop foreign key temp_ibfk_1;
    

4. 数据更新

1. 插入数据

  1. 使用INSERT...VALUES语句插入单行或多行元组数据

    INSERT [INTO] table_name [(column_name, ...)]
    {VALUE | VALUES} ({expr | DEFAULT}, ...), (), ...
    

    使用INSERT VALUES语句向数据库mysql_test的表customers中插入这样一行完整数据:(901,张山,F,北京市,朝阳区)

    mysql> insert into mysql_test.customers
        -> value ('zhangshan', 901, 'f', 'beijing', 'chaoyang');
    

    使用INSERT VALUES语句向数据库mysql_test的表customers中插入这样一行数据,要求该数据目前只用明确给出c_namec_city的信息,即“李四” “武汉”,而c_id由系统自动生成,c_sex选用默认值,另外c_address的值暂不确定,可不用指定。

    mysql> insert into mysql_test.customers
        -> values ('lisi', 0, default, 'wuhan', null);
    
  2. 使用INSERT...SET语句插入部分列值数据

    INSERT [INTO] table_name
    SET column_name = {expr | DEFAULT}, ...
    

    使用INSERT VALUES语句向数据库mysql_test的表customers中插入数据:名为李四,城市武汉,性别默认

    mysql> insert into mysql_test.customers
        -> set c_name = 'lisi', c_city = 'wuhan', c_sex = default;
    
  3. INSERT...SELECT语句插入子查询数据

    INSERT [INTO] table_name [(column_name, ...)]
    SELECT ...
    //例
    mysql> insert into mysql_test.customers
        -> select * from mysql_test.temp_customers;
    

2. 删除数据

使用DELETE语句删除一行或多行数据

DELETE FROM table_name
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

使用DELETE语句删除数据库mysql_test的表customers中客户名为lisi的信息:

mysql> delete from mysql_test.customers
    -> where c_name = 'lisi';

3. 修改数据

使用UPDATE语句修改更新一个表中的数据

UPDATE table_name
    SET column_name1 = {expr | default}, [column_name2 = {expr | default}], ...
    [WHERE where_condition]
    [ORDER BY...]
    [LIMIT row_count]

使用UPDATE语句删除数据库mysql_test的表customers中姓名为zhangshan的客户的地址更新为wuhan

mysql> update mysql_test.customers
    -> set c_address = 'wuhan'
    -> where c_name = 'zhangshan';

5. 数据查询

1. SELECT语句

SELECT
    [ALL | DISTINCT | DISTINCTROW]
    select_expr, [select_expr...]
    FROM table_references
    [WHERE where_condition]
    [GROUP BY {column_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]]
    [HAVING where_condition]
    [ORDER BY {column_name | expr | position} [ASC | DESC], ...]
    [LIMIT {[offset] row_count | row_count OFFSET offset}]
子句 说明 是否必须使用
SELECT 要返回的列或表达式
FROM 从中检索数据的表 仅在从表检索数据时会用
WHERE 行级过滤
GROUP BY 分组说明 仅在按组计算聚合时使用
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数

2. 列的选择与指定

  1. 选择指定的列

    查询数据库mysql_test的表customers中各个客户的姓名、性别和住址信息

    mysql> select c_id, c_name
        -> form mysql_test.customers;
    
  2. 选择全部的信息

    查询数据库mysql_test的表customers中各个客户的所有信息

    mysql> select * from mysql_test.customers;
    
  3. 定义并使用列的别名

    column_name [AS] column_alias
    //例
    mysql> select c_name, c_address as dizhi, c_contact
        -> from mysql_test.customers;
    
  4. 替换查询结果集中的数据

    CASE
    WHEN 条件1 THEN 表达式1
        WHEN 条件2 THEN 表达式2
        ...
    ELSE 表达式
    END [AS] column_alias
    

    查询数据库mysql_test的表customers中客户的c_name列和c_sex列,要求判断结果集中c_sex列的值,如果该列的值为m,则显示输出nan,否则为nv,同时在结果集的显示中将c_sex列用xingbie标注:

    mysql> select c_name,
        -> case
        -> when c_sex = 'm' then 'nan'
        -> else 'nv'
        -> end as 'xingbie'
        -> from mysql_test.customers;
    
  5. 计算列值

    查询数据库mysql_test的表customers中每个客户的c_name列,c_sex列,以及对c_id列加上数字100后的值:

    mysql> select c_id + 100, c_name, c_sex
        -> from mysql_test.customers;
    
  6. 聚合函数

    函数名 说明
    COUNT 求组中项数,返回INT类型整数
    MAX 求最大值
    MIN 求最小值
    SUM 返回表达式中所有值的和
    AVG 求组中值的平均值
    STD或STDDEV 返回给定表达式中所有值的标准值
    VARIANCE 返回给定表达式中所有值的方差
    GROUP_CONCAT 返回由属于一组的列值连接组合而成的结果
    BIT_AND 逻辑与
    BIT_OR 逻辑或
    BIT_XOR 逻辑异或

3. FROM子句与多表连接查询

  1. 交叉连接,又称笛卡尔积

    mysql> SELECT * FROM table1 CROSS JOIN table2;
    //或
    mysql> SELECT * FROM table1, table2;
    
  2. 内连接

    SELECT some_column FROM table1 INNER JOIN table2
    ON some_condition;
    

    根据学生基本信息登记表tb_student和学生成绩表tb_score,使用内连接查询每个学生及其选课成绩的详细信息:

    mysql> select *
        -> from tb_student inner join tb_score
        -> on tb_student.stuendtNO = tb_score.studentNO;
    
  3. 外连接

    • 左外连接:在FROM子句中使用关键字LEFT OUTER JOINLEFT JOIN
    • 右外连接:在FROM子句中使用关键字RIGHT OUTER JOINRIGHT JOIN

    根据学生基本信息登记表tb_student和学生成绩表tb_score,使用内连接查询每个学生及其选课成绩的详细信息:

    mysql> select *
        -> from tb_student left join tb_score
        -> on tb_student.stuendtNO = tb_score.studentNO;
    

4. WHERE子句与条件查询

  1. 比较运算

    在数据库mysql_test的表customers中查找所有男性客户的信息:

    mysql> select * from mysql_test.customers
        -> where c_sex = 'm';
    
  2. 判定范围

    1. 当查询的过滤条件被限定在值的某个范围时,可以使用关键字BETWEEN

      expression [NOT] BETWEEN expression1 AND expression2;
      

      在数据库mysql_test的表customers中,查询客户id号在900905之间的客户信息:

      mysql> select * from mysql_test.customers 
          -> where c_id between 900 and 905;
      
    2. 使用关键字IN,可以指定一个值的枚举表,该表中会列出所有可能的值:

      expression IN (expression [..., n]);
      

      查询id为901,904,905的客户信息:

      mysql> select * from mysql_test.customers
          -> where c_id in (901, 904, 905);
      
    3. 判定空值

      expression IS [NOT] NULL;
      

      在数据库mysql_test的表customers中,查询联系方式为空的客户姓名:

      mysql> select c_name from mysql_test.customers
          -> where c_contact is null;
      
    4. 子查询

      • 表子查询
      • 行子查询
      • 列子查询
      • 标量子查询
      1. 结合关键字IN使用的子查询

        主要用于判定一个给定值是否存在于子查询的结果集中:

        expression [NOT] IN (subquery);
        

        查询任意所选课程成绩高于80分的学生的学号和姓名:

        mysql> select s_no, s_name from mysql_test.t_stu
            -> where s_no in 
            -> (
            -> select s_no from mysql_test.t_score
            -> where score > 80
            -> );
        
      2. 结合比较运算符使用的子查询

        expression {= | < | <= | > | >= | != | <> | <=>} {ALL | SOME | ANY} (subquery)
        
      3. 结合关键字EXISTS使用的子查询

        子查询的结果集不为空,则返回TRUE,否则返回FALSE

        EXISTS (subquery)
        

5. GROUP BY子句与分组查询

/*
column_name:指定用于分组的选择列
expr:指定用于分组的表达式
position:指定用于分组的列在select语句结果集中的位置,通常是一个正整数
ASC/DESC:排序方式,默认asc
WITH ROLLUP:指定在结果集中不仅包含由group by子句分组后的数据行,还包含各分组的汇总行,可以得到每个分组以及每个分组级别的值
*/
GROUP BY {column_name | expr | position} [ASC | DESC], ... [WITH ROLLUP]

在数据库mysql_test的表customers中获取一个数据结果集,要求该结果集中分别包含每个相同地址的男性客户人数和女性客户人数:

mysql> select c_address, c_sex, count(*) as 'renshu'
    -> from mysql_test.customers
    -> group by c_address, c_sex;

在数据库mysql_test的表customers中获取一个数据结果集,要求该结果集中分别包含每个相同地址的男性客户人数和女性客户人数,总人数以及客户的总人数:

mysql> select c_address, c_sex, count(*) as 'renshu'
    -> from mysql_test.customers
    -> group by c_address, c_sex
    -> with rollup;

6. HAVING子句

HAVING where_condition
HAVING子句 VS WHERE子句
过滤分组 过滤数据行
可以包含聚合函数 不可以包含聚合函数
在数据分组后进行过滤 在数据分组前进行过滤

在数据库mysql_test的表customers中查找一类客户信息,要求在返回的结果集中,列出相同客户地址中满足客户人数少于3的所有客户性别及其对应地址:

mysql> select c_address, c_sex
    -> from mysql_test.customers
    -> group by c_address, c_sex
    -> having count(*) <= 3;

7. ORDER BY子句

ORDER BY {column_name | expr | position} [ASC | DESC], ...
ORDER BY 子句 VS GROUP BY 子句
排序产生的输出 分组行,但输出可能不是分组的顺序
任意列都可以使用 只可能使用选择列或表达式列
不一定需要 若与聚合函数一起使用列或表达式,则必须使用

在数据库mysql_test的表customers中依次按照客户姓名和地址的降序方式输出客户的姓名和性别:

mysql> select c_name, c_sex from mysql_test.customers
    -> order by c_name desc, c_address desc;

8. LIMIT子句

使用LIMIT子句限制被SELECT语句返回的行数

/*
offset:可选项,默认0。指定返回数据的第一行在select语句结果集中的偏移量,必须是非负的整数常量
row_count:指定返回数据的行数,必须是非负的整数常量
row_count OFFSET offset:从offset+1行开始,取row_count行
*/
LIMIT {[offset] row_count | row_count OFFSET offset}

在数据库mysql_test的表customers中查找从第2位开始的3位客户的id号和姓名:

mysql> select c_id, c_name from mysql_test.customers
    -> limit 1, 3;
//或
mysql> select c_id, c_name from mysql_test.customers
    -> limit 3 offset 1;

6. 视图

1. 视图的定义

视图是数据库中的一个对象,它是数据库管理系统提供给用户的以多种角度观察数据库中数据的一种机制。

视图不是数据库中真实的表,而是一张虚拟的表,其自身并不存储数据。

2. 使用视图的优点:

  1. 集中分散数据
  2. 简化查询语句
  3. 重用sql语句
  4. 保护数据安全
  5. 共享所需数据
  6. 更改数据格式

3. 创建视图

使用CREATE VIEW创建视图

/*
view_name:指定视图的名称
column_list:可选项,为每个列指定名称
select_statement:指定select语句
[WITH [CASCADED | LOCAL] CHECK OPTION]:可选项,指定在可更新视图上所进行的修改都需要符select_statement中指定的限制条件
*/
CREATE [OR REPLACE] VIEW view_name [(column_list)]
    AS select_statement
    [WITH [CASCADED | LOCAL] CHECK OPTION]

在数据库mysql_test的创建视图customers_view,要求该视图包含客户信息表customers中所有男客户的信息,并且要求保证今后对该视图数据的修改都必须符合客户性别为男性这个条件:

create or replace view mysql_test.customers_view
as select * from mysql_test.customers where c_sex = 'm'
with check option;

4. 删除视图

DROP VIEW [IF EXISTS] view_name [, view_name, ...]
[RESTRICT CASCADE]

5. 修改视图定义

使用ALTER VIEW语句对已有视图的定义(结构)进行修改

ALTER VIEW view_name [column_list]
AS select_statement
[WITH [CASCADED | LOACL] CHECK OPTION]

6. 查看视图定义

使用SHOW CREATE VIEW语句查看已有视图的定义(结构)

SHOW CREATE VIEW view_name;

7. 更新视图数据

  1. 使用INSERT语句通过视图向基本表插入数据

    在数据库mysql_test中,向视图customers_view插入记录:(909,‘zhouming’,‘wuhan’,‘hongshanqu’):

    INSERT INTO mysql_test.customers_view
    VALUES (909, 'zhouming', 'wuhan', 'hongshanqu');
    
  2. 使用UPDATE语句通过视图修改基本表的数据

    将视图customers_view中所有c_address列更新为shanghai

    UPDATE mysql_test.customers_view
    SET c_address = 'shanghai';
    
  3. 使用DELETE语句通过视图删除基本表的数据

    删除customers_view中姓名为zhouming的客户信息

    DELETE FROM mysql_test.customers_view
    WHERE c_name = ‘zhouming’;
    

8. 查询视图数据

在视图customers_view中客户id为905号的客户姓名及其地址:

SELECT c_name, c_address
FROM mysql_test.customers_view
WHERE c_id = 905;

你可能感兴趣的:(四、SQL与关系数据库基本操作)