Hamge

学习记录

导航

SQL 入门了解

SQL

随着应用程序的功能越来越复杂,数据量越来越大,如何管理这些数据就成了大问题:

  • 读写文件并解析出数据需要大量重复代码;
  • 从成千上万的数据中快速查询出指定数据需要复杂的逻辑。

如果每个应用程序都各自写自己的读写数据的代码,一方面效率低,容易出错,另一方面,每个应用程序访问数据的接口都不相同,数据难以复用。

所以,数据库作为一种专门管理数据的软件就出现了。应用程序不需要自己管理数据,而是通过数据库软件提供的接口来读写数据。至于数据本身如何存储到文件,那是数据库软件的事情,应用程序自己并不关心:

SQL是结构化查询语言的缩写,用来访问和操作数据库系统。SQL语句既可以查询数据库中的数据,也可以添加、更新和删除数据库中的数据,还可以对数据库进行管理和维护操作。不同的数据库,都支持SQL,这样,我们通过学习SQL这一种语言,就可以操作各种不同的数据库。

虽然SQL已经被ANSI组织定义为标准,不幸地是,各个不同的数据库对标准的SQL支持不太一致。并且,大部分数据库都在标准的SQL上做了扩展。也就是说,如果只使用标准SQL,理论上所有数据库都可以支持,但如果使用某个特定数据库的扩展SQL,换一个数据库就不能执行了。例如,Oracle把自己扩展的SQL称为PL/SQL,Microsoft把自己扩展的SQL称为T-SQL

现实情况是,如果我们只使用标准SQL的核心功能,那么所有数据库通常都可以执行。不常用的SQL功能,不同的数据库支持的程度都不一样。而各个数据库支持的各自扩展的功能,通常我们把它们称之为“方言”。

总的来说,SQL语言定义了这么几种操作数据库的能力:

DDL:Data Definition Language

DDL允许用户定义数据,也就是创建表、删除表、修改表结构这些操作。通常,DDL由数据库管理员执行。

DML:Data Manipulation Language

DML为用户提供添加、删除、更新数据的能力,这些是应用程序对数据库的日常操作。

DQL:Data Query Language

DQL允许用户查询数据,这也是通常最频繁的数据库日常操作。

 

一、数据模型

数据库按照数据结构来组织、存储和管理数据,实际上,数据库一共有三种模型:

  • 层次模型
  • 网状模型
  • 关系模型

层次模型就是以“上下级”的层次关系来组织数据的一种方式,层次模型的数据结构看起来就像一颗树:

 


 

网状模型把每个数据节点和其他很多节点都连接起来,它的数据结构看起来就像很多城市之间的路网:

 

关系模型把数据看作是一个二维表格,任何数据都可以通过行号+列号来唯一确定,它的数据模型看起来就是一个Excel表:

 

  主流关系数据库

   目前,主流的关系数据库主要分为以下几类:

  1. 商用数据库,例如:OracleSQL ServerDB2等;
  2. 开源数据库,例如:MySQLPostgreSQL等;
  3. 桌面数据库,以微软Access为代表,适合桌面应用程序使用;
  4. 嵌入式数据库,以Sqlite为代表,适合手机应用和桌面程序。
 

二、数据类型

对于一个关系表,除了定义每一列的名称外,还需要定义每一列的数据类型。关系数据库支持的标准数据类型包括数值、字符串、时间等:

名称类型说明
INT 整型 4字节整数类型,范围约+/-21亿
BIGINT 长整型 8字节整数类型,范围约+/-922亿亿
REAL 浮点型 4字节浮点数,范围约+/-1038
DOUBLE 浮点型 8字节浮点数,范围约+/-10308
DECIMAL(M,N) 高精度小数 由用户指定精度的小数,例如,DECIMAL(20,10)表示一共20位,其中小数10位,通常用于财务计算
CHAR(N) 定长字符串 存储指定长度的字符串,例如,CHAR(100)总是存储100个字符的字符串
VARCHAR(N) 变长字符串 存储可变长度的字符串,例如,VARCHAR(100)可以存储0~100个字符的字符串
BOOLEAN 布尔类型 存储True或者False
DATE 日期类型 存储日期,例如,2018-06-22
TIME 时间类型 存储时间,例如,12:20:59
DATETIME 日期和时间类型 存储日期+时间,例如,2018-06-22 12:20:59

上面的表中列举了最常用的数据类型。很多数据类型还有别名,例如,REAL又可以写成FLOAT(24)。还有一些不常用的数据类型,例如,TINYINT(范围在0~255)。各数据库厂商还会支持特定的数据类型,例如JSON

选择数据类型的时候,要根据业务规则选择合适的类型。通常来说,BIGINT能满足整数存储的需求,VARCHAR(N)能满足字符串存储的需求,这两种类型是使用最广泛的。

 三、数据查询

  3.1、基本查询   

    SELECT * FROM <表名>;  -->>查询这个表的数据

    使用SELECT * FROM <表名>;时,SELECT是关键字,表示将要执行的一个查询,*表示"所有列",FROM表示将要从那个表查询

    SELECT不仅可以查询表,还能用作计算,如SELECT 10+20,可以计算出结果为30,但是,不带FROM的SELECT语句还有一个用途,就是用来判断当前到数据库的连接是否有效。许多检测工具会执行一条SELECT 1;来从测试数据库是否连接。

    注:查询结果是一个二维表,它包含列名和每一行数据。

 

  3.2、条件查询

     使用SELECT * FROM <表名>可以查询到一张表的所有记录。但是,很多时候,我们并不希望获得所有记录,而是根据条件选择性地获取指定条件的记录。

     SELECT语句可以通过WHERE条件来设定查询条件,查询结果是满足查询条件的记录。

    SELECT * FROM <表名> WHERE <条件表达式> ;

    条件表达式可以分为:  1、<条件一> AND  <条件二>     -->   表达满足条件一并且满足条件二。     如:SELECT * FROM students WHERE score >= 80 AND  gender = ' M ';

                2、<条件一>  OR <条件二>       -->   表达满足条件一或者满足条件二。     如:SELECT * FROM students WHERE score >= 80 OR gender=' M ';

                3、 NOT <条件>    -->   表达"不符合该条件" 。     如:SELECT * FROM students WHERE NOT class_id = 2;

                4、可以使用 " ( ) "包含上面多个条件。      如:SELECT * FROM students WHERE ( score < 80 OR score > 90 ) AND gender = ' M ';

                5、BETWEEN   -->   BETWEEN 60 AND 90 表示在60~90之前(包含)的查询。

    注:如果不加括号,条件运算按照NOT、AND、OR的优先级进行,即NOT 优先级最高,其次AND,最后OR 。

 

  3.3、投影查询        

     使用SELECT * FROM <表名> WHERE <条件>可以选出表中的若干条记录。我们注意到返回的二维表结构和原表是相同的,即结果集的所有列与原表的所有列都一一对应。

        如果我们只希望返回某些列的数据,而不是所有列的数据,我们可以用SELECT 列1, 列2, 列3 FROM ...,让结果集仅包含指定列。这种操作称为投影查询。

     SELECT <列名>, <列名>  <更换的列名> FROM <表名>; 

     使用SELECT 列1, 列2, 列3 FROM ...时,还可以给每一列起个别名,这样,结果集的列名就可以与原表的列名不同。它的语法是SELECT 列1 别名1, 列2 别名2, 列3 别名3 FROM ...

       如:SELECT id, score points, name FROM students;     这里查询了id,score,name并且把score重命名为point,而id,name列名保持不变。

 

    3.4、排序

    使用SELECT查询时,你可能注意到,查询结果集通常是按照id排序的,也就是根据主键排序。这也是大部分数据库的做法。如果我们要根据其他条件排序怎么办?可以加上ORDER BY子句。

    SELECT <列名>,...,<列名> FROM <表名> ORDER BY <列名>; 

    如:SELECT id, name, gender, score FROM students ORDER BY score;         ->       这里查询了id,name,gender和score,但结果是按照score的低到高排序的。

    如果score列有相同的数据,要进一步排序,可以继续添加列名。例如,使用ORDER BY score DESC, gender表示先按score列倒序,如果有相同分数的,再按gender列排序

    注:ORDER BY 排序是默认从低到高,若要从高到低则需要在ORDER BY后面添加DESC关键字(ASC升序,DESC降序)。 即 SELECT id, name, gender, score FROM students ORDER BY score DESC;  

      如果有WHERE子句,那么ORDER BY子句要放到WHERE子句后面。

   3.5、分页查询 

    使用SELECT查询时,如果结果集数据量很大,比如几万行数据,放在一个页面显示的话数据量太大,不好查看,不如分页显示,每次显示100条。

    要实现分页功能,实际上就是从结果集中显示第1~100条记录作为第1页,显示第101~200条记录作为第2页,以此类推。

    SELECT * FROM <表名> LIMIT  <X>  OFFSET <Y> ;         X ->每页显示最多几条数据,Y -> 显示第几条数据索引值

     如:SELECT id, name, gender, score FROM students ORDER BY score DESC LIMIT 3 OFFSET 0;       ->     每页显示3行,显示第一页,数据索引从0开始。如果要查询第二页,那么需要跳过前三条数据,即需要OFFSET设为3。如此类推

    注:OFFSET超过了查询的最大数量并不会报错,而是得到一个空的结果集。

      OFFSET是可选的,如果只写LIMIT 10,那么相当于LIMIT 10 OFFSET 0。(数据总量为10条)分页查询需要先确定每页的数量和当前页数,然后确定LIMITOFFSET的值。

 

   3.6、聚合查询

    对于统计总数、平均数这类计算,SQL提供了专门的聚合函数,使用聚合函数进行查询,就是聚合查询,它可以快速获得结果。 

    SELECT  <函数>(<列名>)  <新列名> FROM <表名>;

    所有的UDAF(即聚合函数)都应该支持分组查询,内置的聚合函数有:

函数  说明
COUNT 统计记录数 注意和count(*)的区别
SUN 某一列的总值,该列必须为数值类型  
AVG 某一列的平均值,该列必须为数值类型
MAX 最大值
MIN 最小值
FIRST 第一条记录
LAST 最后一条记录
    
    注:1、COUNT(*)事实上和COUNT(<主键>)一样。
      2、SUN和AVG仅能用于对数值的计算。
      3、MAX和MIN不仅可以用于数值也能运用于字符,会返回排序最后和排序最前的字符。
      4、如果聚合查询的WHERE条件没有匹配到任何行,COUNT()会返回0,而SUM()、AVG()、MIN()和MAX()会返回NULL。

 

     GROUP BY

    SELECT <列名>, COUNT(*) <新列名> FROM <表名> GROUP BY <列名>;    (这里两个列名是同一个列名,先由GROUP BY将表根据列名进行分组在逐一进行COUNT统计)

    如:SELECT class_id, COUNT(*) num FROM students GROUP BY class_id;

    若将那么放入其中,即SELECT name, class_id, COUNT(*) num FROM students GROUP BY class_id;返回的结果集中name的值会为NULL。

    因为在任意一个分组中,只有class_id都相同,name是不同的,SQL引擎不能把多个name的值放入一行记录中。因此,聚合查询的列中,只能放入分组的列。

     

3.6、多表查询

 

四、增、删、改

  4.1、增(INSERT  INTO)   

    INSERT INTO <表名> (字段1,字段2,...)VALUES (值1,值2,...);

 

idclass_idnamegenderscore
1 1 小明 M 90
2 1 小红 F 95
3 1 小蓝 M 88
    
       
      向students表插入一条新记录,先列举出需要插入的字段名称,然后在VALUES子句中依次写出对应字段的值:
       ---->>   INSERT INTO students (class_id , name , gender , score) VALUES (2,'小绿','M',80)
 
 
idclass_idnamegenderscore
1 1 小明 M 90
2 1 小红 F 95
3 1 小蓝 M 88
4 2 小绿 M 80

    注:1、我们并没有列出id字段,也没有列出id字段对应的值,这是因为id字段是一个自增主键,它的值可以由数据库自己推算出来。此外,如果一个字段有默认值,那么在INSERT语句中也可以不出现。

      2、字段顺序不必和数据库表的字段顺序一致,但值的顺序必须和字段顺序一致。也就是说,可以写INSERT INTO students (score , gender , name , class_id) ...,但是对应的VALUES就得变成(80, 'M', '小绿', 2)

    

   4.2、删(DELETE)

       DELETE FROM <表名> WHERE <条件>;

                 注意到DELETE语句的WHERE条件也是用来筛选需要删除的行,因此可以通过条件的筛选一次删除多条记录。

      若WHERE没有匹配到合适的记录,DELETE不会报错,当然也不会有数据被删除。

      最后,要注意不带WHERE筛选条件的DELETE语句会删除整个表的数据。

 

 

   4.3、改(UPDATE)

       UPDATE <表名> SET 字段1=值1, 字段2=值2, ... WHERE ...;

idclass_idnamegenderscore
1 1 小明 M 66
      
 
 
      更新studentsid=1的记录的namescore这两个字段,先写出UPDATE students SET name='大明', score=66,然后在WHERE子句中写出需要更新的行的筛选条件id=1
      ----- >> UPDATE students SET name = '大明' ,score= 66 WHERE id = 1;           (如 SET score = score + 10 可给当前字段的score加上10)
 
 
idclass_idnamegenderscore
1 1 大明 M 66

      
      最后,要注意不带WHERE筛选条件的UPDATE语句会更新整个表的数据。
      

posted on 2019-03-13 10:35  Hamge  阅读(414)  评论(0编辑  收藏  举报