zoukankan      html  css  js  c++  java
  • mysql 查询重点难点操作

    1.1. 排序查询

    通过order by语句,可以将查询出的结果进行排序。暂时放置在select语句的最后。

    格式:

    SELECT * FROM 表名 ORDER BY 排序字段 ASC|DESC;
     ASC 升序 (默认)
     DESC 降序

    #1.使用价格排序(降序)
    SELECT * FROM product ORDER BY price DESC;

    #2.在价格排序(降序)的基础上,以分类排序(降序)
    SELECT * FROM product ORDER BY price DESC,category_id DESC;

    #3.显示商品的价格(去重复),并排序(降序)
    SELECT DISTINCT price FROM product ORDER BY price DESC;

     

     

    1.2. 聚合查询

    之前我们做的查询都是横向查询,它们都是根据条件一行一行的进行判断,而使用聚合函数查询是纵向查询,它是对一列的值进行计算,然后返回一个单一的值;另外聚合函数会忽略空值。

    今天我们学习如下五个聚合函数:

    聚合函数

    作用

    count()

    统计指定列不为NULL的记录行数;

    sum()

    计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0

    max()

    计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;

    min()

    计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;

    avg()

    计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0

     

    实例:

    #1 查询商品的总条数
    SELECT COUNT(*) FROM product;

    #2 查询价格大于200商品的总条数
    SELECT COUNT(*) FROM product WHERE price > 200;


    #3 查询分类为'c001'的所有商品的总和
    SELECT SUM(price) FROM product WHERE category_id = 'c001';

    #4 查询分类为'c002'所有商品的平均价格
    SELECT AVG(price) FROM product WHERE category_id = 'c002';

    #5 查询商品的最大价格和最小价格
    SELECT MAX(price),MIN(price) FROM product;

     

    limit语句

    1.3. 分组查询

    分组查询是指使用group by字句对查询信息进行分组。

    格式:

    SELECT 字段1,字段2… FROM 表名 GROUP BY分组字段 HAVING 分组条件;

    分组操作中的having子语句,是用于在分组后对数据进行过滤的,作用类似于where条件。

    having与where的区别:

    1).having是在分组后对数据进行过滤.,where是在分组前对数据进行过滤

    2).having后面可以使用分组函数(统计函数),where后面不可以使用分组函数。

    实例:

    #1 统计各个分类商品的个数
    SELECT category_id ,COUNT(*) FROM product GROUP BY category_id ;

    #2 统计各个分类商品的个数,且只显示个数大于1的信息
    SELECT category_id ,COUNT(*) FROM product GROUP BY category_id HAVING COUNT(*) > 1;

     

    1.4. 分页查询

      分页查询在项目开发中常见,由于数据量很大,显示屏长度有限,因此对数据需要采取分页显示方式。例如数据共有30条,每页显示5条,第一页显示1-5条,第二页显示6-10条。

    l 格式:

    SELECT 字段1,字段2... FROM 表名 LIMIT M,N
    M: 整数,表示从第几条索引开始,计算方式 (当前页-1)*每页显示条数
    N: 整数,表示查询多少条数据 offset 偏移量(每页显示多少条数据)
    SELECT 字段1,字段2... FROM 表名 LIMIT 0,5
    SELECT 字段1,字段2... FROM 表名 LIMIT 5,5

     

    #查询product表的前5条记录

    SELECT *  FROM product LIMIT 0,5

     select * from Customer LIMIT 10;--检索前10行数据,显示1-10条数据
    select * from Customer LIMIT 1,10;--检索从第2行开始,累加10条id记录,共显示id为2....11
    select * from Customer limit 5,10;--检索从第6行开始向前加10条数据,共显示id为6,7....15
    select * from Customer limit 6,10;--检索从第7行开始向前加10条记录,显示id为7,8...16

    3、反例

    追加:

    select * from Customer limit 10,5;--检索从第10行开始向前加5条数据,共显示id为11,12...15

     

    1.5. insert into select语句

     INSERT INTO SELECT 语句从一个表复制数据,然后把数据插入到一个已存在的表中。

     基本语法:

    INSERT INTO table2
    SELECT column_name(s)
    FROM table1;

     

    实例:

    create table product2(
     pid int primary key,
     pname varchar(20),
     price double
    );

     

    insert into product2 select pid,pname,price from product where category_id = 'c001';

     

     

     

    2. 多表操作

    实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系,接下来我们将在单表的基础上,一起学习多表方面的知识。

     

    2.1. 表与表之间的关系

    l 一对多关系:

    n 常见实例:客户和订单,分类和商品,部门和员工.

    n 一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键.

     

    l 一对一关系:

    一个学生对应一个学生档案材料,或者每个人都有唯一的身份证编号。

    l 一对多关系:

    一个学生只属于一个班,但是一个班级有多名学生。

    l 多对多关系:

    一个学生可以选择多门课,一门课也有多名学生。

     

    2.2. 外键约束

    现在我们有两张表“分类表”和“商品表”,为了表明商品属于哪个分类,通常情况下,我们将在商品表上添加一列,用于存放分类cid的信息,此列称为:外键

     

     

    此时“分类表category”称为:主表,“cid”我们称为主键。“商品表products”称为:从表,category_id称为外键。我们通过主表的主键和从表的外键来描述主外键关系,呈现就是一对多关系。

    外键特点:

    u 从表外键的值是对主表主键的引用。

    u 从表外键类型,必须与主表主键类型一致。

     

    l 声明外键约束

    语法:

    alter table 从表 add [constraint] [外键名称] foreign key (从表外键字段名) references 主表 (主表的主键);


    [外键名称] 用于删除外键约束的,一般建议“_fk”结尾
     alter table 从表 drop foreign key 外键名称

     

    l 使用外键目的:

    n 保证数据完整性

     

     

    2.3. 一对多操作

    2.3.1. 分析

     

    l category分类表,为一方,也就是主表,必须提供主键cid

    l products商品表,为多方,也就是从表,必须提供外键category_id

     

    2.3.2. 实现:分类和商品

     

    ###创建分类表
    create table category(

      cid varchar(32) PRIMARY KEY ,
      cname varchar(100)  #分类名称
    );


    # 商品表
    CREATE TABLE products (

      pid varchar(32) PRIMARY KEY,
      name VARCHAR(40) ,
      price DOUBLE ,
      category_id varchar(32)
    );

    #添加约束
    alter table products add constraint product_fk foreign key (category_id) references category (cid);

     

    2.3.3. 操作

    #1 向分类表中添加数据
    INSERT INTO category (cid ,cname) VALUES('c001','服装');


    #2 向商品表添加普通数据,没有外键数据,默认为null
    INSERT INTO products (pid,pname) VALUES('p001','商品名称');


    #3 向商品表添加普通数据,含有外键信息(category表中存在这条数据)
    INSERT INTO products (pid ,pname ,category_id) VALUES('p002','商品名称2','c001');


    #4 向商品表添加普通数据,含有外键信息(category表中不存在这条数据) -- 失败,异常
    INSERT INTO products (pid ,pname ,category_id) VALUES('p003','商品名称2','c999');


    #5 删除指定分类(分类被商品使用) -- 执行异常
    DELETE FROM category WHERE cid = 'c001';

     

    3. 多表查询

     

    CREATE TABLE category (
      cid VARCHAR(32) PRIMARY KEY ,
      cname VARCHAR(50)
    );
    CREATE TABLE products(
      pid VARCHAR(32) PRIMARY KEY ,
      pname VARCHAR(50),
      price INT,
      flag VARCHAR(2),    #是否上架标记为:1表示上架、0表示下架
      category_id VARCHAR(32),

      CONSTRAINT products_fk FOREIGN KEY (category_id) REFERENCES category (cid)
    );

     

    3.1. 初始化数据

    #分类
    INSERT INTO category(cid,cname) VALUES('c001','家电');

    INSERT INTO category(cid,cname) VALUES('c002','服饰');
    INSERT INTO category(cid,cname) VALUES('c003','化妆品');
    #商品
    INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p001','联想',5000,'1','c001');

    INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p002','海尔',3000,'1','c001');
    INSERT INTO products(pid, pname,price,flag,category_id) VALUES('p003','雷神',5000,'1','c001');

    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p004','JACK JONES',800,'1','c002');
    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p005','真维斯',200,'1','c002');
    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p006','花花公子',440,'1','c002');
    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p007','劲霸',2000,'1','c002');

    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p008','香奈儿',800,'1','c003');
    INSERT INTO products (pid, pname,price,flag,category_id) VALUES('p009','相宜本草',200,'1','c003');

     

     

     

    3.2. 多表查询

    1. 交叉连接查询(基本不会使用-得到的是两个表的乘积) [了解]

    语法:select * from A,B;

    1. 内连接查询(使用的关键字 inner join  -- inner可以省略)

    n 隐式内连接:select * from A,B where 条件;

    n 显示内连接:select * from A inner join B on 条件;

    1. 外连接查询(使用的关键字 outer join -- outer可以省略)

    n 左外连接:left outer join

    u select * from A left outer join B on 条件;

    n 右外连接:right outer join

    select * from A right outer join B on 条件;

     

    #1.查询哪些分类的商品已经上架
    #隐式内连接
    SELECT DISTINCT c.cname FROM category c , products p

     WHERE c.cid = p.category_id AND p.flag = '1';

    #内连接
    SELECT DISTINCT c.cname FROM category c

     INNER JOIN products p ON c.cid = p.category_id
     WHERE p.flag = '1';

     

    #2.查询所有分类商品的个数
    #左外连接
    INSERT INTO category(cid,cname) VALUES('c004','奢侈品');

    SELECT cname,COUNT(category_id) FROM category c
     LEFT OUTER JOIN products p
      ON c.cid = p.category_id
     GROUP BY cname;

     

    下面通过一张图说明连接的区别:

     

     

    3.3. 子查询

    子查询:一条select语句结果作为另一条select语法一部分(查询条件,查询结果,表等)。

    select ....查询字段 ... from ... 表.. where ... 查询条件

     

    #3 子查询, 查询“化妆品”分类上架商品详情
    #隐式内连接
    SELECT p.* FROM products p , category c

     WHERE p.category_id=c.cid AND c.cname = '化妆品';

    #子查询
    ##作为查询条件
    SELECT * FROM products p

     WHERE p.category_id =
     (
      SELECT c.cid FROM category c
       WHERE c.cname='化妆品'
     );

     ##作为另一张表
     SELECT * FROM products p ,

       (SELECT * FROM category WHERE cname='化妆品') c
      WHERE p.category_id = c.cid;

     

    #查询“化妆品”和“家电”两个分类上架商品详情
    SELECT * FROM products p

     WHERE p.category_id in
     (

      SELECT c.cid FROM category c
       WHERE c.cname='化妆品' or c.name='家电'
     );

     

     

     

    4. MySql索引(书本目录)    

    4.1. 概述

    索引是 MySQL 中一种十分重要的数据库对象。它是数据库性能调优技术的基础,常用于实现数据的快速检索。
       索引就是根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表,实质上是一张描述索引列的列值与原表中记录行之间一一对应关系的有序表。


    在 MySQL 中,通常有以下两种方式访问数据库表的行数据:

    1) 顺序访问

    顺序访问是在表中实行全表扫描从头到尾逐行遍历,直到在无序的行数据中找到符合条件的目标数据。这种方式实现比较简单,但是当表中有大量数据的时候,效率非常低下。

    2) 索引访问

    索引访问是通过遍历索引来直接访问表中记录行的方式。使用这种方式的前提是对表建立一个索引,在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快捷地查找到数据。索引存储了指定列数据值的指针,根据指定的排序顺序对这些指针排序。

    例如,在学生基本信息表 students 中,如果基于 student_id 建立了索引,系统就建立了一张索引列到实际记录的映射表,当用户需要查找 student_id 为 12022 的数据的时候,系统先在 student_id 索引上找到该记录,然后通过映射表直接找到数据行,并且返回该行数据。因为扫描索引的速度一般远远大于扫描实际数据行的速度,所以采用索引的方式可以大大提高数据库的工作效率。

    4.2. 索引的分类

    根据存储方式的不同,MySQL 中常用的索引在物理上分为以下两类。

    B-树索引

    B-树索引又称为 BTREE 索引,目前大部分的索引都是采用 B-树索引来存储的。B-树索引是一个典型的数据结构基于这种树形数据结构,表中的每一行都会在索引上有一个对应值。因此,在表中进行数据查询时,可以根据索引值一步一步定位到数据所在的行。

    哈希索引

    哈希(Hash)一般翻译为“散列”,也有直接音译成“哈希”的,就是把任意长度的输入(又叫作预映射,pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值
    HASH 索引不是基于树形的数据结构查找数据,而是根据索引列对应的哈希值的方法获取表的记录行


    根据索引的具体用途,MySQL 中的索引在逻辑上分为以下 3 类:

    普通索引

    普通索引是最基本的索引类型,唯一任务是加快对数据的访问速度,没有任何限制。创建普通索引时,通常使用的关键字是 INDEX 或 KEY。

    唯一性索引

    唯一性索引是不允许索引列具有相同索引值的索引。如果能确定某个数据列只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字 UNIQUE 把它定义为一个唯一性索引。
    创建唯一性索引的目的往往不是为了提高访问速度,而是为了避免数据出现重复

    主键索引

    主键索引是一种唯一性索引,即不允许值重复或者值为空,并且每个表只能有一个主键。主键可以在创建表的时候指定,也可以通过修改表的方式添加,必须指定关键字 PRIMARY KEY。

     

    4.3. 索引的操作

    4.3.1. 普通索引:

    4.3.1.1. 创建索引

    方式1-直接创建

    CREATE INDEX indexName ON mytable(username([length]));

    如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length。

     

    方式2-修改表结构(添加索引)

    ALTER table tableName ADD INDEX indexName(columnName)

     

    方式3-创建表的时候直接指定

    CREATE TABLE mytable(  
    ID INT NOT NULL,   
    username VARCHAR(16) NOT NULL,  
    INDEX indexName(username(length))  

    );  

     

    4.3.1.2. 查询索引

    #1、查看表中所有索引

    SHOW INDEX FROM table_name;

    #2、查看数据库所有索引
    SELECT * FROM mysql.`innodb_index_stats` a WHERE a.`database_name` = '数据库名';


    #2、查看某一表索引
    SELECT * FROM mysql.`innodb_index_stats` a WHERE a.`database_name` = '数据库名' and a.table_name like '%表名%';

     

    4.3.1.3. 删除索引

    DROP INDEX [indexName] ON mytable;

    alter table mytable drop index indexName;

     

    4.3.2. 唯一索引

    它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:

    4.3.2.1. 创建索引

    方式1-直接创建

    CREATE UNIQUE INDEX indexName ON mytable(username(length))

    方式2-修改表结构(添加索引)

    ALTER table mytable ADD UNIQUE [indexName] (username(length))

    方式3-创建表的时候直接指定

    CREATE TABLE mytable(  
    ID INT NOT NULL,   
    username VARCHAR(16) NOT NULL,  
    UNIQUE [indexName] (username(length))  

    );  

     

    4.3.2.2. 删除索引

    DROP INDEX [indexName] ON mytable;

    alter table mytable drop index indexName;

    4.3.3. 主键索引

     主键索引的操作就是主键约束的操作,之前已经讲过,在这里不做描述。

     

    4.4. 索引的使用原则和注意事项

    虽然索引可以加快查询速度,提高 MySQL 的处理性能,但是过多地使用索引也会造成以下弊端:

    l 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

    l 除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。

    l 当对表中的数据进行增加、删除和修改的时候,索引也要动态地维护,这样就降低了数据的维护速度。

    l 对于那些在查询中很少使用或参考的列不应该创建索引。因为这些列很少使用到,所以有索引或者无索引并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度,并增大了空间要求。

    5. MySql开窗函数

    5.1. 概述

    MySql在8.0的版本增加了对开窗函数的支持,终于可以在MySql使用开窗函数了。

    开窗函数的语法结构:

     #Key word :Partiton by & order by
    <开窗函数> over ([PARTITION by <列清单>]

                         Order by <排序用列清单>)

     

    Mysql中支持的开窗函数有很多,这里重点给大家介绍三个:row_number(),rank()

    ,dense_rank()

     

    5.2. 开窗函数介绍

     row_number(),rank(),dense_rank()这三个函数都是用于返回结果集的分组内每行的排名

    三者区别:

    row_number:不管排名是否有相同的,都按照顺序1,2,3…..n
    rank:排名相同的名次一样,同一排名有几个,后面排名就会跳过几次 
    dense_rank:排名相同的名次一样,且后面名次不跳跃

     

     

     

    5.3. 案例

    数据准备:

    create table employee (empid int,ename varchar(20) ,deptid int ,salary decimal(10,2));


    insert into employee values(1,'刘备',10,5500.00);
    insert into employee values(2,'赵云',10,4500.00);
    insert into employee values(2,'张飞',10,3500.00);
    insert into employee values(2,'关羽',10,4500.00);

    insert into employee values(3,'曹操',20,1900.00);
    insert into employee values(4,'许褚',20,4800.00);
    insert into employee values(5,'张辽',20,6500.00);
    insert into employee values(6,'徐晃',20,14500.00);

    insert into employee values(7,'孙权',30,44500.00);
    insert into employee values(8,'周瑜',30,6500.00);
    insert into employee values(9,'陆逊',30,7500.00);

     

    对employee表中按照deptid进行分组,并对每一组的员工按照薪资进行排名:

    SELECT
      empid,

      ename,
      deptid,
      salary,
      row_number() over (PARTITION BY deptid ORDER BY salary DESC) AS row_number1,
      rank() OVER (PARTITION BY deptid ORDER BY salary desc) AS rank2,
      dense_rank() OVER (PARTITION BY deptid ORDER BY salary desc) AS dense_rank3
    FROM
     employee;

     

     

     

     

     

     

     

     

     

     

     

     

  • 相关阅读:
    C语言volatile关键字的用法
    UDP广播包
    进程和线程的区别
    Unix/Linux进程间通信
    虚拟空间,malloc
    自我介绍
    java初始化顺序
    java 队列基础操作
    java IO基础操作
    Python中的Tab补全功能添加
  • 原文地址:https://www.cnblogs.com/shan13936/p/13703179.html
Copyright © 2011-2022 走看看