SQL简单总结

SQL简单总结

NOTE:本文所用的都以postgreSQL为例,对标准SQL语句进行简单的总结,语法等细节详细参考《SQL基础教程》,下称《教程》。下面的代码例子都基于下表:

1. 数据库

1.1 分类

  1. 层次数据库

  2. 关系数据库(最常用)

  3. 面向对象数据库

  4. xml数据库

  5. 键值存储数据库

    1.2 结构

2. 什么是SQL

SQL是为了操作数据库而开发的语言。

国际标准化组织(ISO)为 SQL 制定了相应的标准,以此为基准的SQL 称为标准 SQL 。大多数SQL语法都类似,但是不同的数据库的SQL语法还是不一样的。

3. 表的创建、删除、更新

目前在关系型数据库中,用来管理数据的二维表称之为(table)。表存储在数据库中,一个数据库中可以有多个表。

  • 创建

    数据库的创建:

    ​ 语法:CREATE DATABASE <数据库名称>;

    表的创建:

    ​ 语法:

    CREATE TABLE <表名>
    ( <列名1> <数据类型> <该列所需约束>,
    <列名2> <数据类型> <该列所需约束>,
    <列名3> <数据类型> <该列所需约束>,
    <列名4> <数据类型> <该列所需约束>,
    .
    .
    .
    <该表的约束1>, <该表的约束2>,……);
    

    ​ eg. 创建一个名为Product的表,存储商品ID、商品名、类型、销售价格、购买价格等列。并且,所有列必须指定数据类型。

    CREATE TABLE Product
    (product_id CHAR(4) NOT NULL,
     product_name VARCHAR(100) NOT NULL,
     product_type VARCHAR(32) NOT NULL,
     sale_price INTEGER ,
     purchase_price INTEGER ,
     regist_date DATE ,
     PRIMARY KEY (product_id));	  -- 主键约束
    

    其中:数据类型有:

    1. 数字型
      1. INTEGER。只能存储整数,不能存储小数。
    2. 字符型
      1. CHAR(10)。定长字符串,长度为10,不足的用空格补齐。
      2. VARCHAR(10)。变长字符串,最大长度为10,不足的时候不用空格补齐。
    3. 日期型
      1. DATE。存储日期的类型。

    约束条件指的是对存入数据的限制。如:NOT NULL,指的就是必须存入数据,不能为NULL。

  • 删除

    • DROP

      语法:DROP TABLE <表名>; 。需要注意的是删除的表是不能恢复的。

    • DELETE

      DELETE FROM <表名>; 。执行完后效果是清空表中的数据行,但表还是存在的。

      DELETE FROM <表名> WHERE <条件>; 。指定条件的删除其中的行。

  • 更新

    • 表定义更新:ALTER TABLE <表名> ADD COLUMN <列的定义>;。eg.

    ALTER TABLE Product ADD COLUMN product_name_pinyin VARCHAR(100); --添加列
    ALTER TABLE Product DROP COLUMN product_name_pinyin; --删除列

    
    -  向表中插入数据
    
    插入一行:`INSERT INTO ProductIns (product_id, product_name, product_type, sale_price, purchase_price, regist_date) VALUES ('0005', '高压锅','厨房用具', 6800, 5000, '2009-01-15');  `
    
    省略列清单的单行插入:
    
    ````sql
    -- DML :插入数据
    BEGIN TRANSACTION;
    INSERT INTO Product VALUES ('0001', 'T恤衫', '衣服',1000, 500, '2009-09-20');
    INSERT INTO Product VALUES ('0002', '打孔器', '办公用品',500, 320, '2009-09-11');
    INSERT INTO Product VALUES ('0003', '运动T恤', '衣服',4000, 2800, NULL);
    INSERT INTO Product VALUES ('0004', '菜刀', '厨房用具',3000, 2800, '2009-09-20');
    INSERT INTO Product VALUES ('0005', '高压锅', '厨房用具',6800, 5000, '2009-01-15');
    INSERT INTO Product VALUES ('0006', '叉子', '厨房用具',500, NULL, '2009-09-20');
    INSERT INTO Product VALUES ('0007', '擦菜板', '厨房用具',880, 790, '2008-04-28');
    INSERT INTO Product VALUES ('0008', '圆珠笔', '办公用品',100, NULL,'2009-11-11');
    COMMIT;
    

    插入多行:

    INSERT INTO ProductIns VALUES 
       ('0002', '打孔器', '办公用品', 500, 320, '2009-09-11'),
       ('0003', '运动T恤', '衣服', 4000, 2800, NULL),
       ('0004', '菜刀', '厨房用具', 3000, 2800, '2009-09-20'); 
    
    • 表复制

      -- 将商品表中的数据复制到商品复制表中
      INSERT INTO ProductCopy (product_id, product_name, product_type, 
      sale_price, purchase_price, regist_date)
      SELECT product_id, product_name, product_type, sale_price, 
      purchase_price, regist_date
      FROM Product;
      
    • UPDATE

      更新所有的列:

      --更新所有的列为'2009-10-10'
      UPDATE Product
      SET regist_date = '2009-10-10';
      

      当然也可以通过WHERE来指定需要更新的行。

      多行更新:

      -- 使用逗号对列进行分隔排列
      UPDATE Product
      SET sale_price = sale_price * 10,
      purchase_price = purchase_price / 2
      WHERE product_type = '厨房用具';
      
      -- 将列用()括起来的清单形式
      UPDATE Product
      SET (sale_price, purchase_price) = (sale_price * 10, 
      purchase_price / 2)
      WHERE product_type = '厨房用具';
      
  • 事务:事务就是需要在同一个处理单元中执行的一系列更新处理(INSERT/DELETE/UPDATE)的集合

    语法:

    事务开始语句;
    DML语句①;
    DML语句②;
    DML语句③;
    ...
    事务结束语句( COMMIT或者ROLLBACK) ;
    

    eg.

    BEGIN TRANSACTION;
        -- 将运动T恤的销售单价降低1000日元
        UPDATE Product
        SET sale_price = sale_price - 1000
        WHERE product_name = '运动T恤';
        -- 将T恤衫的销售单价上浮1000日元
        UPDATE Product
        SET sale_price = sale_price + 1000
        WHERE product_name = 'T恤衫';
    COMMIT;
    

    在事务最后,COMMIT代表提交事务,一旦提交,无法恢复到事务开始前的状态。ROLLBACK代表取消事务,一旦回滚,数据库会恢复到事务开始前的状态。

    事务的ACID特性:

    1. 原子性(Atomicity):所包含的更新处理要么全部执行,要么完全不执行 。
    2. 一致性(Consistency):事务中包含的处理要满足数据库提前设置的约束 。如NOT NULL约束,如果更新操作违反约束,则该事务会ROLLBACK。
    3. 隔离性(Isolation):指的是保证不同事务之间互不干扰的特性
    4. 持久性(Durability):指的是在事务(不论是提交还是回滚)结束后, DBMS 能够保证该时间点的数据状态会被保存的特性。

4. 查询

4.1 一般查询

  • SELECT

    语法:SELECT <列名>,……FROM <表名>; 。eg. SELECT product_id, product_name, purchase_price FROM Product;

    SELECT * FROM Product; 表示选取所有的列。

    SELECT product_id as id FROM Product;AS可以为列起别名。

  • DISTINCT

    效果:删除重复的行,达到去重效果。

    语法:SELECT DISTINCT product_type FROM Product;

  • WHERE(筛选行)

    效果:通过制定WHERE后面的条件,来筛选出想要的数据行。

    语法:SELECT <列名>, ……FROM <表名> WHERE <条件表达式>;

    eg. SELECT product_name, product_type FROM Product WHERE product_type = '衣服';

  • GROUP BY

    效果:把表分成几组,然后再进行汇总处理

    语法:

    SELECT <列名1>, <列名2>, <列名3>, ……
    FROM <表名>
    GROUP BY <列名1>, <列名2>, <列名3>, ……;
    

    eg.

    SELECT product_type, COUNT(*)
    FROM Product
    GROUP BY product_type;
    
  • HAVING(筛选组)

    效果:通过制定HAVING后面的条件,来筛选出想要的组。

  • ORDER BY

    效果:对结果进行排序

    语法:

    SELECT <列名1>, <列名2>, <列名3>, ……
    FROM <表名>
    ORDER BY <排序基准列1>, <排序基准列2>, ……
    

    eg.

    SELECT product_id, product_name, sale_price, purchase_price
    FROM Product
    ORDER BY sale_price;
    

    ORDER BY后面可以跟多个列。如col1, col2...,优先按col1排列,如果存在col1相同的情况下,再按col2排列。ORDER BY默认为升序排列ASC,如果要降序,则需在列的后面添加DESC。eg. ORDER BY col1 desc;

    在ORDER BY子句中可以使用SELECT子句中定义的别名。

4.2 子查询

子查询通俗的将就是查询语句的嵌套。也可以理解为是一次性的视图。eg.

SELECT product_type, cnt_product
FROM ( SELECT product_type, COUNT(*) AS cnt_product
FROM Product
GROUP BY product_type ) AS ProductSum;

其中括号里的查询就是子查询。执行顺序:先执行子查询,然后在子查询的基础上做查询。

标量子查询:必须而且只能返回 1 行 1列的结果 。

--WHERE字句中不能使用聚合函数,这时可以用标量子查询完成这一效果
SELECT product_id, product_name, sale_price
FROM Product
WHERE sale_price > (SELECT AVG(sale_price)
						FROM Product);

关联子查询

--选取Product中每种类型的商品中销售单价大于该类商品平均售价的商品
SELECT product_type, product_name, sale_price
FROM Product AS P1 
WHERE sale_price > (SELECT AVG(sale_price)
                    FROM Product AS P2 
                    WHERE P1.product_type = P2.product_type			--关联
                    GROUP BY product_type);

5. 视图VIEW

在SQL中,表是存储在硬盘上的,我们通过SELECT语句查询所需的数据。但是使用视图时,不会将数据保存到任何地方。实际上,视图保存的是SELECT语句。当我们从视图中读取数据时,视图内部其实在执行SELECT语句。所以使用视图有2大有点:①节省存储空间;②自动更新(表中数据更新,视图结果也自动更新)

创建视图:

CREATE VIEW 视图名称(<视图列名1>, <视图列名2>, ……)
AS
<SELECT语句>

eg.

CREATE VIEW ProductSum (product_type, cnt_product)
AS
SELECT product_type, COUNT(*)
FROM Product
GROUP BY product_type;

使用视图来查询:

-- 确认创建好的视图
SELECT product_type, cnt_product
FROM ProductSumJim;

我们可以再视图的基础上再创建视图,即多重视图。但应避免这种情况,因为多重视图会降低SQL性能。

删除视图:DROP VIEW ProductSum;

6. 运算符

  • 算术运算符:+、-、*、/。注意:所有包含 NULL 的计算,结果肯定是 NULL。

  • 比较运算符:=、<>、>、>=、<、<=。注意:不能对NULL使用比较运算符 。

  • 逻辑运算符:NOT、AND、OR。注意:AND运算符的优先级高于OR运算符。想要优先执行OR运算符时可以使用括号。

    但是当运算符涉及到NULL时,情况就不太一样了,如下图:

7. 函数

  • 聚合函数(聚合函数会将NULL排除在外。但COUNT(*)例外,并不会排除NULL。)

    • COUNT:计算表中的记录数(行数)

      eg. SELECT COUNT(*) FROM Product;

      注意:COUNT(*)会得到包含NULL的数据 行数,而COUNT(<列名>)会得到NULL之外的数据行数。

    • SUM:计算表中数值列中数据的合计值

    • AVG:计算表中数值列中数据的平均值

    • MAX:求出表中任意列中数据的最大值

    • MIN:求出表中任意列中数据的最小值

  • 算术函数

    • 算数运算符:+、-、*、/。注意:所有包含 NULL 的计算,结果肯定是 NULL。
    • ABS(数值):绝对值。
    • MOD(被除数,除数):求余。
    • ROUND(对象数值,保留小数的位数) :四舍五入。
  • 字符串函数

    • 字符串1||字符串2 :拼接。eg. 'code' || 'mao' = 'codemao'
    • LENGTH(字符串) :求字符串长度。
    • LOWER(字符串) /UPPER(字符串):大小写转换。
    • REPLACE(对象字符串,替换前的字符串,替换后的字符串) :字符串替换。eg. REPLACE('Abc', 'bc', 'BC') = 'ABC'
    • SUBSTRING(对象字符串 FROM 截取的起始位置 FOR 截取的字符数) :子串截取。注意:这里字符串索引从1开始。
  • 日期函数:

    • CURRENT_DATE :返回当前日期。如2009-12-13 。
    • CURRENT_TIME :返回当前时间。如17:26:50.995+09 。
    • CURRENT_TIMESTAMP:返回当前日期和时间。
    • EXTRACT(日期元素 FROM 日期) :截取出日期数据中的一部分,例如“年“,“月”,或者“小时”“秒”等 ,其返回值是数值类型,不是日期类型。
  • 转换函数

    • CAST(转换前的值 AS 想要转换的数据类型) :相当于C语言中的强制类型转换。

    • COALESCE(数据1,数据2,数据3……) :该函数会返回可变参数 A 中左侧开始第 1个不是 NULL 的值。参数个数是可变的,因此可以根据需要无限增加。

      --通过这个函数,可以实现将NULL转换为其他值
      SELECT COALESCE(NULL, 1) AS col_1,
      	COALESCE(NULL, 'test', NULL) AS col_2
      FROM TABLE;
      
  • 谓词

    谓词可以理解为是一种返回真值的函数。

    • LIKE:字符串的部分一致查询。

      'abc' LIKE 'ab%' 返回 真。  	其中 % 代表0个字符及以上的任意字符串
      'abdd' LIKE 'ab__' 返回 真。	其中 _ 代表任意一个字符串
      
    • BETWEEN:范围查询

      150 BETWEEN 100 AND 1000返回真。

    • IS NULL、IS NOT NULL:判断是否为空。不能用=判断。

    • IN、NOT IN:相当于OR的简便用法。

      SELECT product_name, purchase_price
      FROM Product
      WHERE purchase_price IN (320, 500, 5000);
      
    • EXISTS:有点难理解,可理解为存在与否。eg.

      --列出Product中存在于名为‘000C’的商店中的商品
      SELECT product_name, sale_price
      FROM Product AS P 
      WHERE EXISTS (SELECT *
              FROM ShopProduct AS SP 
              WHERE SP.shop_id = '000C'
              AND SP.product_id = P.product_id);
      
  • CASE(SQL中的条件分支)

    • 搜索CASE表达式

      SELECT product_name,
          CASE WHEN product_type = '衣服'
          THEN 'A : ' || product_type
          WHEN product_type = '办公用品'
          THEN 'B : ' || product_type
          WHEN product_type = '厨房用具'
          THEN 'C : ' || product_type
          ELSE NULL
          END AS abc_product_type				--END不可省略
      FROM Product;
      
    • 行列转换

      -- 对按照商品种类计算出的销售单价合计值进行行列转换
      SELECT SUM(CASE WHEN product_type = '衣服'
      		THEN sale_price ELSE 0 END) AS sum_price_clothes,
      	   SUM(CASE WHEN product_type = '厨房用具'
      		THEN sale_price ELSE 0 END) AS sum_price_kitchen,
             SUM(CASE WHEN product_type = '办公用品'
      		THEN sale_price ELSE 0 END) AS sum_price_office
      FROM Product;
      
  • 窗口函数(OLAP函数)

    窗口函数兼具分组和排序两种功能。

    在使用范围上:原则上窗口函数只能在SELECT子句中使用

    语法:<窗口函数> OVER ([PARTITION BY <列清单>] ORDER BY <排序用列清单>)

    RANK():计算排序时,如果存在相同位次的记录,则会跳过之后的位次。eg. 有3条记录并列第一时:1,1,1,4······。eg.

    -- 结果根据product_type分组,每组内部按照sale_price排序,ranking列显示排名顺序
    SELECT product_name, product_type, sale_price,
        RANK () OVER (PARTITION BY product_type
        ORDER BY sale_price) AS ranking
    FROM Product;
    

    其中,PARTITION BY(可以省略,不分组)能够设定排序的对象范围, ORDER BY 能够指定按照哪一列、何种顺序进行排序。

    DENSE_RANK():同样是计算排序,即使存在相同位次的记录,也不会跳过之后的位次。 eg. 有 3 条记录排在第 1 位时:1 位、1 位、1 位、2 位……

    ROW_NUMBER():赋予唯一的连续位次。eg. 有 3 条记录排在第 1 位时:1 位、2 位、3 位、4 位……

    SELECT product_name, product_type, sale_price,
        RANK () OVER (ORDER BY sale_price) AS ranking,
        DENSE_RANK () OVER (ORDER BY sale_price) AS dense_ranking,
        ROW_NUMBER () OVER (ORDER BY sale_price) AS row_num
    FROM Product;
    

    另外,所有的聚合函数都能作为窗口函数使用,只是语法不一样。如:

    SELECT product_id, product_name, sale_price,
    	SUM (sale_price) OVER (ORDER BY product_id) AS current_sum
    FROM Product;
    
    效果:
    product_id | product_name | sale_price | current_sum
    ---------- +-----------   +------------+------------
    0001 	  | T恤衫          | 1000 	 | 1000 ←1000
    0002 	  | 打孔器 		| 500 		 | 1500 ←1000+500
    0003      | 运动T恤 		| 4000 		 | 5500 ←1000+500+4000
    0004      | 菜刀 			 | 3000 	  | 8500 ←1000+500+4000+3000
    0005      | 高压锅 		| 6800 		 | 15300
    0006      | 叉子 			 | 500 		  |	 15800
    0007      | 擦菜板 		| 880 		 | 16680
    0008      | 圆珠笔 		| 100 		 | 16780
    

    计算移动平均

    SELECT product_id, product_name, sale_price,
        AVG (sale_price) OVER (ORDER BY product_id
        		ROWS 2 PRECEDING) AS moving_avg
    FROM Product;
    

    其中:ROWS 2 PRECEDING指的是统计当前行及前2行的数据;同理还有ROWS 2 FOLLOWING统计当前行及后2行数据;ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING 统计当前行、前一行和后一行的数据。

  • GROUPING运算符

    只使用GROUP BY子句和聚合函数是无法同时得出小计和合计的,这时GROUPING运算符上场了。

    • ROLLUP

      -- 结果会有每组销售价格小计和所有销售价格的总计
      SELECT product_type, SUM(sale_price) AS sum_price
      FROM Product
      GROUP BY ROLLUP(product_type);
      

      相当于做了下面2个操作:

      ① GROUP BY ():会得到全部数据的合计行的记录。称为超级分组记录(super group row)。

      ② GROUP BY (product_type)

    • GROUPING

      这部分比较难理解,详见《教程》。

8. 集合运算

8.1 表加减

表加减仅仅是对表中数据行的操作。

  • UNION(并集)

    表的加法。但是不包括2张表中的重复行。

    --Product表 + Product2表
    SELECT product_id, product_name
    FROM Product
    UNION
    SELECT product_id, product_name
    FROM Product2;
    

    注意:

    1. 作为运算对象的记录的列数必须相同
    2. 作为运算对象的记录中列的类型必须一致
    3. 可以使用任何SELECT语句,但ORDER BY子句只能在最后使用一次

    ALL选项:

    SELECT product_id, product_name
    FROM Product
    UNION ALL			-- 包含重复行,就是2张表简单的相加
    SELECT product_id, product_name
    FROM Product2;
    
  • INTERSECT(交集)

    选取2张表中的公共部分。

  • EXCEPT(差集)

    -- Product中去除Product2中的行
    SELECT product_id, product_name
    FROM Product
    EXCEPT
    SELECT product_id, product_name
    FROM Product2
    ORDER BY product_id;
    

    注意,差集的2张表被减数和减数位置不一样,结果亦不同。

8.2 联结

联结是将其他表中的列添加过来,进行“添加列”的集合运算 。

  • INNER JOIN

    内联结:以2张表同时存在的列(称之为公共列)为桥梁,将只存在于一张表中的列汇集到结果里。但是只会汇集公共列里2张表同时存在的值的行。

    --选出同时存在于SP和P中的product_id数据行
    SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, 
    P.sale_price
    FROM ShopProduct AS SP 
        INNER JOIN Product AS P 
        ON SP.product_id = P.product_id;
    
  • OUTER JOIN

    外联结:和内联结类似,也是扩大列,但与内联结不同的是,它会汇集其中一张表中所有公共列的行。用关键字RIGHT和LEFT来指定哪个表是主表(使用 LEFT 时 FROM 子句中写在左侧的表是主表,使用 RIGHT时右侧的表是主表),最终结果会包含主表里所有的数据。

    --在内联结的基础上,加上只存在于P中的product_id的行。
    SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name, 
    P.sale_price
    FROM ShopProduct AS SP RIGHT OUTER JOIN Product AS P 
    	ON SP.product_id = P.product_id;
    
  • CROSS JOIN(笛卡尔积)

    交叉联结。在实际应用中很少使用,但是是所有联结的基础。

    --SP有13行,P有8行。则结果有13×8行
    SELECT SP.shop_id, SP.shop_name, SP.product_id, P.product_name
    FROM ShopProduct AS SP CROSS JOIN Product AS P;
    
posted on 2021-11-11 22:51  rogerg6  阅读(115)  评论(0)    收藏  举报