zoukankan      html  css  js  c++  java
  • 单点突破:MySQL之基础

    前言

    开发环境:MySQL5.7.31

    本文并不是mysql语法语句的教程或者笔记,如果初学MySQL,想要看sql的教程或者学习各种语法语句规范,可以看看一千行MySQL学习笔记或者MySQL教程|菜鸟教程

    SQL命令

    SQL命令分可以分为四组:DDL、DML、DCL和TCL。

    DDL

    DDL是数据定义语言(Data Definition Language)的简称,它处理数据库schemas和描述数据应如何驻留在数据库中。

    • CREATE:创建数据库及其对象(如表,索引,视图,存储过程,函数和触发器)
    • ALTER:改变现有数据库的结构
    • DROP:从数据库中删除对象
    • TRUNCATE:从表中删除所有记录,包括为记录分配的所有空间都将被删除
    • COMMENT:添加注释
    • RENAME:重命名对象

    常用命令如下:

    # 建表
    CREATE TABLE sicimike (
      id int(4) primary key auto_increment COMMENT '主键ID',
      name varchar(10) unique,
      age int(3) default 0,
      identity_card varchar(18)
      # PRIMARY KEY (id) // 也可以通过这种方式设置主键
      # UNIQUE KEY (name) // 也可以通过这种方式设置唯一键
      # key/index (identity_card, col1...) // 也可以通过这种方式创建索引
    ) ENGINE = InnoDB;
    
    # 设置主键
    alter table sicimike add primary key(id);
    
    # 删除主键
    alter table sicimike drop primary key;
    
    # 设置唯一键
    alter table sicimike add unique key(column_name);
    
    # 删除唯一键
    alter table sicimike drop index column_name;
    
    # 创建索引
    alter table sicimike add [unique/fulltext/spatial] index/key index_name (identity_card[(len)] [asc/desc])[using btree/hash]
    create [unique/fulltext/spatial] index index_name on sicimike(identity_card[(len)] [asc/desc])[using btree/hash]
    example: alter table sicimike add index idx_na(name, age);
    
    # 删除索引
    alter table sicimike drop key/index identity_card;
    drop index index_name on sicimike;
    
    # 查看索引
    show index from sicimike;
    
    # 查看列
    desc sicimike;
    
    # 新增列
    alter table sicimike add column column_name varchar(30);
    
    # 删除列
    alter table sicimike drop column column_name;
    
    # 修改列名
    alter table sicimike change column_name new_name varchar(30);
    
    # 修改列属性
    alter table sicimike modify column_name varchar(22);
    
    # 查看建表信息
    show create table sicimike;
    
    # 添加表注释
    alter table sicimike comment '表注释';
    
    # 添加字段注释
    alter table sicimike modify column column_name varchar(10) comment '姓名';
    

    DML

    DML是数据操纵语言(Data Manipulation Language)的简称,包括最常见的SQL语句,例如SELECT,INSERT,UPDATE,DELETE等,它用于存储,修改,检索和删除数据库中的数据。

    分页

    -- 查询从第11条数据开始的连续5条数据
    select * from sicimike limit 10, 5
    

    group by

    默认情况下,MySQL中的分组(group by)语句,不要求select返回的列,必须是分组的列或者是一个聚合函数。
    如果select查询的列不是分组的列,也不是聚合函数,则会返回该分组中第一条记录的数据。对比下面两条SQL语句,第二条SQL语句中,cname既不是分组的列,也不是以聚合函数的形式出现。所以在liming这个分组中,cname取的是第一条数据。

    mysql> select * from c;
    +-----+-------+----------+
    | CNO | CNAME | CTEACHER |
    +-----+-------+----------+
    | 1 | 数学 | liming |
    | 2 | 语文 | liming |
    | 3 | 历史 | xueyou |
    | 4 | 物理 | guorong |
    | 5 | 化学 | liming |
    +-----+-------+----------+
    5 rows in set (0.00 sec)
    
    mysql> select cteacher, count(cteacher), cname from c group by cteacher;
    +----------+-----------------+-------+
    | cteacher | count(cteacher) | cname |
    +----------+-----------------+-------+
    | guorong |               1 | 物理 |
    | liming |               3 | 数学 |
    | xueyou |               1 | 历史 |
    +----------+-----------------+-------+
    3 rows in set (0.00 sec)
    

    having

    having关键字用于对分组后的数据进行筛选,功能相当于分组之前的where,不过要求更严格。过滤条件要么是一个聚合函数( ... having count(x) > 1),要么是出现在select后面的列(select col1, col2 ... group by x having col1 > 1)

    多表更新

    update tableA a inner join tableB b on a.xxx = b.xxx set a.col1 = xxx, b.col1 = xxx where ...
    

    多表删除

    delete a, b from tableA a inner join tableB b on a.xxx = b.xxx where a.col1 = xxx and b.col1 = xxx
    

    DCL

    DCL是数据控制语言(Data Control Language)的简称,它包含诸如GRANT之类的命令,并且主要涉及数据库系统的权限,权限和其他控件。

    • GRANT :允许用户访问数据库的权限
    • REVOKE:撤消用户使用GRANT命令赋予的访问权限

    TCL

    TCL是事务控制语言(Transaction Control Language)的简称,用于处理数据库中的事务

    • COMMIT:提交事务
    • ROLLBACK:在发生任何错误的情况下回滚事务

    部分常用函数

    文本处理函数

    • LENGTH() 返回串长度
    • LOWER()将串转换为小写
    • UPPER()将串转换为大写
    • LTRIM()去掉串左边的空格
    • RTRIM()去掉串右边的空格

    日期和时间处理函数

    • DATE() 返回日期的日期部分 SELECT DATE(NOW()) 2017-07-22

    • DATE_FORMAT() 返回格式化的日期和时间串

    • HOUR() 返回一个时间的小时部分

    • MINUTE() 返回一个时间的分钟部分

    • MONTH() 返回一个日期的月份部分

    • NOW() 返回当前日期和时间

    • SECOND() 返回一个时间的秒部分

    • TIME() 返回一个日期时间的时间部分

    • YEAR() 返回一个日期的年份部分

    • SELECT * FROM TABLE WHERE date='2020-02-22' ,如果DATE的类型是DATATIME类型,那么表里一条记录存放的格式应该是2020-02-22 13:45:29,此时这条记录不会被筛选出来,筛选的是2020-02-22 00:00:00

    • 可以采用DATE函数 SELECT * FROM TABLE WHERE DATE(date)='2020-02-22'

    • 时间范围 可以采用DATE函数 SELECT * FROM TABLE WHERE DATE(date) BETWEEN '2020-02-22' AND '2020-03-22'

    数组处理函数

    • ABS() 返回一个数的绝对值
    • COS() 返回一个角度的余弦
    • EXP()返回一个数的指数值
    • MOD()返回除操作的余数
    • PI() 返回圆周率
    • RAND()返回一个随机数
    • SIN()返回一个角度的正弦
    • SQRT() 返回一个数的平方根
    • TAN() 返回一个角度的正切

    聚集函数

    • SELECT AVG(student_score) AS AVG_ PRIVE FROM score 求平均值
    • SELECT COUNT(*) FROM TABLE 表里记录数
    • SELECT COLUMN(name) FROM TABLE 表里列有值的记录数 ,值为NULL不计数
    • SELECT MAX(score) FROM TABLE 查找最大值
    • SELECT MIN(score) FROM TABLE 查找最小值
    • SELECT SUM(count) FROM TABLE 返回指定列的和 SUM(price*count)同样适用

    union和union all

    • union 是对数据进行并集操作,不包括重复行,同时进行默认排序
    • Union all 是对数据进行并集操作,包括重复行,不进行排序

    示例:

    创建两个表

    CREATE TABLE `t_demo` (
      `id` int(32) NOT NULL,
      `name` varchar(255) DEFAULT NULL,
      `age` int(2) DEFAULT NULL,
      `num` int(3) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    
    INSERT INTO `t_demo` VALUES ('1', '张三', '21', '69');
    INSERT INTO `t_demo` VALUES ('2', '李四', '22', '98');
    INSERT INTO `t_demo` VALUES ('3', '王五', '20', '54');
    INSERT INTO `t_demo` VALUES ('4', '赵甜', '22', '80');
    
    CREATE TABLE `t_demo_copy` (
      `id` int(32) NOT NULL,
      `name` varchar(255) DEFAULT NULL,
      `age` int(2) DEFAULT NULL,
      `num` int(3) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    INSERT INTO `t_demo_copy` VALUES ('2', '猪八戒', '22', '98');
    INSERT INTO `t_demo_copy` VALUES ('3', '王五', '20', '54');
    INSERT INTO `t_demo_copy` VALUES ('4', '赵甜', '22', '80');
    INSERT INTO `t_demo_copy` VALUES ('5', '孙悟空', '22', '100');
    INSERT INTO `t_demo_copy` VALUES ('6', '李四', '24', '99');
    

    union结果:

    SELECT * FROM t_demo
    UNION
    SELECT * FROM t_demo_copy
    > OK
    > 时间: 0.008s
    

    union all结果:

    SELECT * FROM t_demo
    UNION ALL
    SELECT * FROM t_demo_copy
    > OK
    > 时间: 0s
    

    结论

    UNION ALL只是简单的将两个结果合并后就返回。如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。

    效率

    从效率上说,UNION ALL 要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复数据且不需要排序时的话,那么就使用UNION ALL。

    引擎

    MyISAM与InnoDB 的区别

    1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,(所以最好把多条SQL语言放在begin和commit之间,组成一个事务);
    • InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败
    • InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构)。 MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的。
    • InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快
      • 那么为什么InnoDB没有了这个变量呢?
      • 因为InnoDB的事务特性,在同一时刻表中的行数对于不同的事务而言是不一样的,因此count统计会计算对于当前事务而言可以统计到的行数,而不是将总行数储存起来方便快速查询。
    • InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
      • InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。如果访问没有命中索引,也无法使用行锁,将要退化为表锁。
    • InnoDB表必须有主键(用户没有指定的话会自己找或生产一个主键),而Myisam可以没有
    • Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYI
      • Innodb:frm是表定义文件,ibd是数据文件
      • Myisam:frm是表定义文件,myd是数据文件,myi是索引文件

    问:2者select count(*)哪个更快,为什么

    myisam更快,因为myisam内部维护了一个计数器,可以直接调取。

    innodb引擎的4大特性

    1. 插入缓冲(insert buffer)
    2. 二次写(double write)
    3. 自适应哈希索引(ahi)
    4. 预读(read ahead)

    char和varchar的区别

    简单来说:

    • char:定长,效率高,一般用于固定长度的表单提交数据存储 ;例如:身份证号,手机号,电话,密码等
    • varchar:不定长,效率偏低

    长度方面:

    char类型的长度是固定的;varchar类型的长度是可变的

    效率方面:

    char类型每次修改的数据长度相同,效率更高;varchar类型每次修改的数据长度不同,效率更低

    存储不同:

    char类型存储的时候是初始预计字符串再加上一个记录字符串长度的字节,占用空间较大;varchar类型存储的时候是实际字符串再加上一个记录字符串长度的字节,占用空间较小。

    补充:char(M)类型的数据列里,每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足.(在检索操作中那些填补出来的空格字符将被去掉)在varchar(M)类型的数据列里,每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节)

    NULL和空值的区别

    占用空间不同

    mysql> select length(NULL), length(''), length('1');
    +--------------+------------+-------------+
    | length(NULL) | length('') | length('1') |
    +--------------+------------+-------------+
    |         NULL |          0 |           1 |
    +--------------+------------+-------------+
    1 row in set (0.00 sec)
    

    说明:空值长度为0,是不占用空间的;NULL的长度为NULL,是占用空间的,因为NULL列需要行中的额外空间来记录它们的值是否为NULL。

    插入/查询方式不同

    • 如果字段设置了NOT NULL,则NULL值是无法插入的,但是可以插入空值
    • 在查询时
      • 查询NULL值列用is NULL去查,总之,查询NULL值建议使用is null/is not null;
      • 查询空值列用 = '',总之,查询空值建议使用 =、!=、<、>等算数运算符

    count() 和 IFNULL(参数1,参数2)

    • 使用 COUNT(字段) 统计会过滤掉 NULL 值,但是不会过滤掉空值。
    • IFNULL有两个参数,如果第一个参数字段是NULL就会返回第二个参数(默认值),否则返回第一个参数字段,空值是不会返回默认值的

    索引的问题

    MySql中如果某一列中含有NULL,那么包含该列的索引就无效了。 --> 这句话是错的

    MySQL可以在含有null的列上使用索引。

    在有NULL值得字段上使用常用的索引,如普通索引、复合索引、全文索引等不会使索引失效。在官网查看在空间索引的情况下,说明了 索引列必须为NOT NULL。

    联接

    join 用于多表中字段之间的联系,语法如下:

    ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona
    

    table1:左表;table2:右表。

    JOIN 按照功能大致分为如下三类:

    INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录。

    LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录。

    RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录。

    注意:mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join.

    left join,right join,inner join,full join之间的区别

    • left join会返回左表的所有行,即使在右表中没有匹配的数据
    • right join会返回右表所有行,即使在左表中没有匹配的数据
    • inner join会返回两个表共有的数据
    • full join会返回两个表所有行,即使没有匹配

    Inner join

    内连接,也叫等值连接,inner join产生同时符合A和B的一组数据。

    mysql> select * from A inner join B on A.name = B.name;
    +----+--------+----+--------+
    | id | name   | id | name   |
    +----+--------+----+--------+
    |  1 | Pirate |  2 | Pirate |
    |  3 | Ninja  |  4 | Ninja  |
    +----+--------+----+--------+
    

    Left join

    mysql> select * from A left join B on A.name = B.name;
    #或者:select * from A left outer join B on A.name = B.name;
    
    +----+-----------+------+--------+
    | id | name      | id   | name   |
    +----+-----------+------+--------+
    |  1 | Pirate    |    2 | Pirate |
    |  2 | Monkey    | NULL | NULL   |
    |  3 | Ninja     |    4 | Ninja  |
    |  4 | Spaghetti | NULL | NULL   |
    +----+-----------+------+--------+
    4 rows in set (0.00 sec)
    

    left join,(或left outer join:在Mysql中两者等价,推荐使用left join.)左连接从左表(A)产生一套完整的记录,与匹配的记录(右表(B)) .如果没有匹配,右侧将包含null。

    如果想只从左表(A)中产生一套记录,但不包含右表(B)的记录,可以通过设置where语句来执行,如下:

    mysql> select * from A left join B on A.name=B.name where A.id is null or B.id is null;
    +----+-----------+------+------+
    | id | name      | id   | name |
    +----+-----------+------+------+
    |  2 | Monkey    | NULL | NULL |
    |  4 | Spaghetti | NULL | NULL |
    +----+-----------+------+------+
    2 rows in set (0.00 sec)
    

    同理,还可以模拟inner join. 如下:

    mysql> select * from A left join B on A.name=B.name where A.id is not null and B.id is not null;
    +----+--------+------+--------+
    | id | name   | id   | name   |
    +----+--------+------+--------+
    |  1 | Pirate |    2 | Pirate |
    |  3 | Ninja  |    4 | Ninja  |
    +----+--------+------+--------+
    2 rows in set (0.00 sec)
    

    求差集:

    根据上面的例子可以求差集,如下:

    SELECT * FROM A LEFT JOIN B ON A.name = B.name
    WHERE B.id IS NULL
    union
    SELECT * FROM A right JOIN B ON A.name = B.name
    WHERE A.id IS NULL;
    # 结果
    +------+-----------+------+-------------+
    | id   | name      | id   | name        |
    +------+-----------+------+-------------+
    |    2 | Monkey    | NULL | NULL        |
    |    4 | Spaghetti | NULL | NULL        |
    | NULL | NULL      |    1 | Rutabaga    |
    | NULL | NULL      |    3 | Darth Vader |
    +------+-----------+------+-------------+
    

    Right join

    mysql> select * from A right join B on A.name = B.name;
    +------+--------+----+-------------+
    | id   | name   | id | name        |
    +------+--------+----+-------------+
    | NULL | NULL   |  1 | Rutabaga    |
    |    1 | Pirate |  2 | Pirate      |
    | NULL | NULL   |  3 | Darth Vader |
    |    3 | Ninja  |  4 | Ninja       |
    +------+--------+----+-------------+
    4 rows in set (0.00 sec)
    

    同left join。

    Cross join

    cross join:交叉连接,得到的结果是两个表的乘积,即笛卡尔积

    笛卡尔(Descartes)乘积又叫直积。假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。可以扩展到多个集合的情况。类似的例子有,如果A表示某学校学生的集合,B表示该学校所有课程的集合,则A与B的笛卡尔积表示所有可能的选课情况。

    mysql> select * from A cross join B;
    +----+-----------+----+-------------+
    | id | name      | id | name        |
    +----+-----------+----+-------------+
    |  1 | Pirate    |  1 | Rutabaga    |
    |  2 | Monkey    |  1 | Rutabaga    |
    |  3 | Ninja     |  1 | Rutabaga    |
    |  4 | Spaghetti |  1 | Rutabaga    |
    |  1 | Pirate    |  2 | Pirate      |
    |  2 | Monkey    |  2 | Pirate      |
    |  3 | Ninja     |  2 | Pirate      |
    |  4 | Spaghetti |  2 | Pirate      |
    |  1 | Pirate    |  3 | Darth Vader |
    |  2 | Monkey    |  3 | Darth Vader |
    |  3 | Ninja     |  3 | Darth Vader |
    |  4 | Spaghetti |  3 | Darth Vader |
    |  1 | Pirate    |  4 | Ninja       |
    |  2 | Monkey    |  4 | Ninja       |
    |  3 | Ninja     |  4 | Ninja       |
    |  4 | Spaghetti |  4 | Ninja       |
    +----+-----------+----+-------------+
    16 rows in set (0.00 sec)
    

    Full join

    mysql> select * from A left join B on B.name = A.name 
        -> union 
        -> select * from A right join B on B.name = A.name;
    +------+-----------+------+-------------+
    | id   | name      | id   | name        |
    +------+-----------+------+-------------+
    |    1 | Pirate    |    2 | Pirate      |
    |    2 | Monkey    | NULL | NULL        |
    |    3 | Ninja     |    4 | Ninja       |
    |    4 | Spaghetti | NULL | NULL        |
    | NULL | NULL      |    1 | Rutabaga    |
    | NULL | NULL      |    3 | Darth Vader |
    +------+-----------+------+-------------+
    6 rows in set (0.00 sec)
    

    drop、delete、truncate

    语法

    • drop table 表名称 drop table dbo.Sys_Test
    • truncate table 表名称 truncate table dbo.Sys_Test
    • delete from 表名称 where 列名称 = 值 delete from dbo.Sys_Test where test='test'

    区别

    • drop删除内容和定义,并释放空间。执行drop语句,将使此表的结构一起删除。
    • truncate (清空表中的数据)。删除内容、释放空间但不删除定义(也就是保留表的数据结构)。与drop不同的是,只是清空表数据而已。truncate不能删除行数据,虽然只删除数据,但是比delete彻底,它只删除表数据。
    • delete与truncate类似,delete也只删除内容、释放空间但不删除定义;但是delete即可以对行数据进行删除,也可以对整表数据进行删除。

    执行速度

    delete语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存,以便进行进行回滚操作。

    所以执行速度一般来说:drop>truncate>delete

    场景

    • 如果想删除表,当然用drop;
    • 如果想保留表而将所有数据删除,如果和事务无关,用truncate即可;
    • 如果和事务有关,或者想触发trigger,还是用delete;

    其他

    • truncate语句执行以后,id标识列还是按顺序排列,保持连续;而delete语句执行后,ID标识列不连续
    • delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,但要注意表空间要足够大,需要手动提交(commit)操作才能生效,可以通过rollback撤消操作。
    • drop和truncate是DDL,会隐式提交,所以,不能回滚,不会触发触发器。

    三大范式

    数据库规范化,又称正规化、标准化,是数据库设计的一系列原理和技术,以减少数据库中数据冗余,增进数据的一致性。

    现在数据库设计最多满足3NF,普遍认为范式过高,虽然具有对数据关系更好的约束性,但也导致数据关系表增加而令数据库IO更易繁忙,原来交由数据库处理的关系约束现更多在数据库使用程序中完成。

    第一范式——(确保每列保持原子性)

    定义:数据库中的所有字段(列)都是单一属性,不可再分的。这个单一属性由基本的数据类型所构成,如整型、浮点型、字符串等。

    第一范式是为了保证列的原子性。数据库表的每一列都是不可分割的原子数据项,而不能是集合、数组、记录等非原子数据项。如果实体中的某个属性有多个值时,必须拆分为不同的属性。

    如下表

    学号 姓名 地址
    1000 小明 福建省泉州市洛江区xx街道100号

    不满足第一范式,应该拆分为

    学号 姓名 街道 门牌号
    1000 小明 福建省 泉州市 洛江区 xx街道 100号

    第二范式——(确保表中的每列都和主键相关)(拆多表)

    定义:数据库中的表不存在非关键字段对任一关键字字段的部分函数依赖

    部分函数依赖是指存在着组合关键字中的某一关键字决定非关键字的情况

    第二范式在满足了第一范式的基础上,消除非主键列对联合主键的部分依赖

    一个数据库表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。订单表和商品表不能设计在一张表里,应该分开两个表,再加一个多对多的商品id和订单id关联表。(一个表只描述一件事情)

    第三范式3NF——(在2NF的基础上加外键)

    第三范式(3NF):必须先满足第二范式(2NF),要求:表中的每一列只与主键直接相关而不是间接相关,(表中的每一列只能依赖于主键);

    例如:订单表中需要有客户相关信息,在分离出客户表之后,订单表中只需要有一个用户id即可(外键),而不能有其他的客户信息。因为其他的客户信息直接关联于用户id,而不是直接与订单id直接相关。

    订单表中的用户信息不直接设计字段,设计一个用户id字段再外键关联用户表即可。

  • 相关阅读:
    tar打包如何不打包某一个文件夹(排除某些文件夹)
    第一个SpringBoot应用
    Linux(以RHEL7为例)下添加工作区的方法|| The Way To Add Workspace On Linux
    Linux(以centos7为例)下自动挂载NTFS硬盘
    基于Moodle的IT课程辅助教育平台搭建
    搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台
    如何利用word2013写图文并茂的博客
    如何安装win10+Red Hat Enterprise Linux双系统?
    课堂练习:ex 4-20
    实验二 函数重载、函数模板、简单类的定义和实现
  • 原文地址:https://www.cnblogs.com/kylinxxx/p/14412413.html
Copyright © 2011-2022 走看看