zoukankan      html  css  js  c++  java
  • mySQL__DDL课堂笔记和练习

    表和库的管理

    #DDL
    /*
    数据定义语言
    库和表的管理
    
    一、库的管理
    创建、修改、删除
    
    二、表的管理
    创建、修改、删除
    
    创建:create
    修改:alter
    删除:drop
    */
    
    
    #【一、库的管理】
    #1、【库的创建】
    /*
    语法:
    create database 【if not exists】库名 【character set 字符集名】;
    */
    #创建库Books
    CREATE DATABASE books;#默认字符集是utf8
    #上述语句重复执行就会报错,下面添加容错性处理
    CREATE DATABASE IF NOT EXISTS books;#如果库已经存在就不再创建
    
    
    #2、【库的修改(库一般不修改)】
    #以下语句不安全,会导致数据丢失,目前已经废弃
    RENAME DATABASE books TO 新库名;
    
    #但是可以修改字符集
    ALTER DATABASE books CHARACTER SET gbk;
    
    
    #3、【库的删除】
    DROP DATABASE books;
    #上述语句重复执行就会报错,下面添加容错性处理
    DROP DATABASE IF EXISTS books; 
    
    
    
    #【二、表的管理】
    #1、表的创建★
    
    /*
    语法:
    create table 【if not exists】表名(
    	列名 列的类型【(长度) 约束】,
    	列名 列的类型【(长度) 约束】,
    	列名 列的类型【(长度) 约束】,
    	...
    	列名 列的类型【(长度) 约束】
    )
    */
    
    #创建表book
    CREATE TABLE book(
    	id INT,#编号
    	bName VARCHAR(20),#图书名  20不能省,最低字符数
    	price DOUBLE,#价格
    	authorId INT,#作者编号
    	publishDate DATETIME#出版日期
    )
    
    DESC book;
    
    #创建表author
    #有容错性处理
    CREATE TABLE IF NOT EXISTS author(
    	id INT,
    	au_name VARCHAR(20),
    	nation VARCHAR(10)
    )
    
    DESC author;
    
    
    
    #2、表的修改
    /*
    语法:
    alter table 表名 change|modify|add|drop column 列名 【类型 约束】;
    alter table 表名 rename to ...
    
    */
    
    
    #(1)修改列名
    /*
    alter table 表名 change column 旧列名 新列名 新/旧类型
    */
    #【将旧列名publishdate修改为新列名pubDat,同时确定pubDate的类型为DATETIME】
    #【column可以省略】
    ALTER TABLE book CHANGE COLUMN publishdate pubDate DATETIME;
    
    
    
    #(2)修改列的类型或约束
    /*
    alter table 表名 modify column 列名 【新类型】【新约束】
    */
    #【将pubDate的类型改为TIMESTAMP】
    ALTER TABLE book MODIFY COLUMN pubDate TIMESTAMP;
    
    
    
    #(3)添加新列
    /*
    alter table 表名 add column 列名 类型【first|after 字段】
    */
    #【为author表添加新列annual,类型为double】
    ALTER TABLE author ADD COLUMN annual DOUBLE;
    #将annual字段放在第一个
    ALTER TABLE author ADD COLUMN annual DOUBLE FIRST;
    #将annual字段放在au_name字段的后面
    ALTER TABLE author ADD COLUMN annual DOUBLE AFTER au_name;
    
    
    
    #(4)删除列
    /*
    alter table 表名 drop column 列名;
    */
    #没有容错性处理exists
    ALTER TABLE author DROP COLUMN annual;
    
    
    
    #(5)修改表名
    /*
    alter table 表名 rename to book_author;
    */
    ALTER TABLE author RENAME TO book_author;
    
    
    
    
    #3、表的删除
    /*
    drop table 【if exists】表名;
    */
    DROP TABLE book_author;
    #容错性处理
    DROP TABLE IF EXISTS book_author;
    #查看当前库中的所有表
    SHOW TABLES;
    
    #容错性处理仅仅在库和表的【删除】和【创建】中有,在列的删除中是没有的
    
    
    #对于创建数据库和数据表有一套通用的写法【先删再建】
    DROP DATABASE IF EXISTS 旧库名;
    CREATE DATABASE 新库名;
    
    DROP TABLE IF EXISTS 旧表名;
    CREATE TABLE 表名(...);
    
    
    
    
    #4、表的复制
    
    #在表author中插入数据
    INSERT INTO author 
    VALUES (1,'村上春树','日本'),
    (2,'莫言','中国'),
    (3,'冯唐','中国'),
    (4,'金庸','中国')
    
    SELECT * FROM author;
    
    #(1)仅仅复制表的结构【不复制数据】
    /*
    create table 表名 like 旧表
    */
    CREATE TABLE copy LIKE author;
    
    SELECT * FROM copy;
    
    
    #(2)复制表的结构+数据
    CREATE TABLE copy2
    SELECT * FROM author;
    
    SELECT * FROM copy2;
    
    
    #(3)只复制部分数据
    CREATE TABLE copy3
    SELECT id,au_name
    FROM author
    WHERE nation='中国';
    
    SELECT * FROM copy3;
    
    
    #思考:仅仅仅仅复制表的部分结构【不复制数据】
    #将where条件设置成谁都不满足,就没有数据
    CREATE TABLE copy4
    SELECT id,au_name
    FROM author
    WHERE 1=2;
    
    SELECT * FROM copy4;
    S
    
    
    #练习:在test库中创建新表,将表departments中的数据插入到新表dept
    CREATE TABLE dept
    SELECT department_id,department_name
    FROM myemployees.departments;
    

    常见数据类型

    #常见数据类型
    /*
    数值型:
    	整数型
    	小数:
    		定点数
    		浮点数
    字符型:
    	较短是文本:char、varchar
    	较长的文本:text、blob(较长的二进制)
    日期型:
    */
    
    
    #一、整型
    /*
    分类:	tinyint		smallint	mediumint	intinteger	bigint
    字节:	1		2		3		4		8
    
    特点:
    (1)默认有符号,若想设置无符号则追加unsigned
    (2)若插入的数值超出了整型的范围,会报out of range异常,并且插入临界值
    (3)如果不设置长度会有默认的长度,这个长度不是范围,而是显示结果中该列的宽度,
    如果不够宽度,那么在有关键字ZEROFILL的情况下,就会用0填充。且加上ZEROFILL后就只支持无符号
    UNSIGNED可以省略
    */
    #1.如何设置无符号和有符号
    DROP TABLE IF EXISTS tab_int;
    CREATE TABLE tab_int(
    	t1 INT(7) ZEROFILL,
    	t2 INT ZEROFILL UNSIGNED #UNSIGNED已经没有意义,默认填充到10位
    );
    DESC tab_int
    
    INSERT INTO tab_int VALUES(-1234,-2345);
    INSERT INTO tab_int VALUES(123,123);
    
    SELECT * FROM tab_int;
    
    
    #二、小数
    /*
    分类:
    1.浮点型
    float(M,D)           double(M,D)
      4字节			8字节
    
    
    2.定点型
    dec(M,D)
    decimal(M,D)
    
    
    
    特点:
    (1)M和D分别代表的意思是:
    M:整数部分的位数+小数部分的位数(如果超出范围则插入临界值)
    D:规定小数部分的位数(补0/四舍五入)
    (2)M和D可以省略,如果是DECIMAL,则M=10,D=0;如果是float和double,则会根据插入的数值的精度来决定精度
    (3)定点型的精度较高,如果要求插入的数值的精度较高如货币运输等则考虑使用
    */
    
    
    #(1)测试:M和D的意思
    CREATE TABLE tab_float(
    	f1 FLOAT(5,2),
    	f2 DOUBLE(5,2),
    	f3 DECIMAL(5,2)
    );
    
    SELECT * FROM tab_float;
    
    INSERT INTO tab_float VALUES(123.45,123.45,123.45);#123.45
    INSERT INTO tab_float VALUES(123.456,123.456,123.456);#123.46 四舍五入 保留2位
    INSERT INTO tab_float VALUES(6123.45,6123.45,6123.45);#999.99 一共6位数>5 插入临界值
    INSERT INTO tab_float VALUES(6123.4,6123.4,6123.4);#999.99 为了保证小数点后有两位数,那么总的数字个数就会大于5
    
    #(2)若将M和D省略
    CREATE TABLE tab_float1(
    	f1 FLOAT,
    	f2 DOUBLE,
    	f3 DECIMAL
    );
    
    INSERT INTO tab_float1 VALUES(1223.4567,1223.4567,1223.4567);#只有DECIMAL有警告
    
    SELECT * FROM tab_float1;#1223.4567 1223.4567 1223  	DECIMAL默认(10,0)
    
    /*
    原则:
    所选的类型越简单越好,能保存的数值越小越好
    */
    
    
    #三、字符型
    /*
    较短的文本:【重点】
    char
    varchar
    
    
    
    其他:
    binary和varbinary用于保存较短的二进制
    enum用于保存枚举
    set用于保存集合
    
    
    
    较长的文本:
    text
    blob(较大的二进制)
    
    特点:
    
    		写法		M的意思				特点			空间的耗费	效率
    char		char(M) 	最大的字符数,可省,默认1	固定长度的字符		耗费		高
    varchar		varchar(M)	最大的字符数,不可省		可变长度的字符		节省		低
    
    */
    
    #枚举型enum
    #只能插入列表中枚举出来的数据,且不区分大小写
    CREATE TABLE tab_char(
    	c1 ENUM('a','b','c')
    );
    
    INSERT INTO tab_char VALUES('a');
    INSERT INTO tab_char VALUES('b');
    INSERT INTO tab_char VALUES('c');
    INSERT INTO tab_char VALUES('m');#插入失败
    INSERT INTO tab_char VALUES('A');
    
    SELECT * FROM tab_char;
    
    
    #set集合
    #可以同时插入多个(二enum每次只能插入一个),不区分大小写
    CREATE TABLE tab_set(
    	s1 SET('a','b','c','d')
    )
    INSERT INTO tab_set VALUES('a');
    INSERT INTO tab_set VALUES('a,b,c');
    
    SELECT * FROM tab_set;
    
    
    
    #四、日期型
    /*
    分类:
    date只保存日期
    time只保存时间
    year只保存年
    
    datetime保存日期+时间
    timestamp保存日期+时间
    
    特点:
    		字节		范围		时区等的影响
    datetime	8		1000---9999	不受
    timestamp	4		1970---2038	受
    */
    
    CREATE TABLE tab_date(
    	t1 DATETIME,
    	t2 TIMESTAMP
    );
    
    INSERT INTO tab_date VALUES(NOW(),NOW());
    
    
    
    #查看当前时区
    SHOW VARIABLES LIKE 'time_zone';#system  【当前系统时区其实就是东八区】
    
    SELECT * FROM tab_date;#插入的时间一样
    
    #将当前时区改为东9区
    SET time_zone='+9:00';
    
    #查看当前时区
    SHOW VARIABLES LIKE 'time_zone';#+9:00   
    
    #再去查询
    SELECT * FROM tab_date;#这时候,刚刚插入的时间就不一样了【东9区比东8区块一个小时】
    

    约束

    #常见约束
    /*
    含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性
    
    分类:六大约束
    	not null:非空,用于保证该字段值不能为空
    	比如:姓名、学号
    	
    	default:默认,用于保证该字段有默认值
    	比如:性别
    	
    	primary key:主键,用于保证该字段的值具有唯一性,并且非空
    	比如:学号、员工编号、部门号等
    	
    	unique:唯一,用于保证该字段的值具有唯一性,可以为空
    	比如:座位号
    	
    	check:检查约束【mysql中不支持】
    	比如年龄、性别,只能在一定范围内,不可以随意输入
    	
    	foreign key:外键,用于限制两个表的关系,用于保证该字段的值,必须来自主表关联列的值
    	比如:员工表、部门表。员工表含中有部门编号,部门表中的部门编号是1~100,那么foreign key
    	就可以限制员工表中的部门编号范围是1~100。foreign key是为员工表添加的约束。
    	
    添加约束的时机:
    	1.创建表时
    	2.修改表时
    	
    约束的添加分类:
    	列级约束
    		六大约束语法上都支持,但是外键约束没有效果
    	表级约束
    		除了非空、默认,其他都支持
    		
    	
    */
    
    
    CREATE TABLE 表名(
    	字段名 字段类型 列级约束,
    	字段名 字段类型,
    	表级约束
    )
    
    
    #一、创建表时添加约束
    #1.添加列级约束
    /*
    直接在字段名和类型后面直接添加  约束类型即可
    只支持:默认、非空、主键、唯一
    */
    
    CREATE DATABASE students;
    
    USE students;
    
    CREATE TABLE stuinfo(
    	id INT PRIMARY KEY,#主键
    	stuName VARCHAR(20) NOT NULL,#非空
    	gender CHAR(1) CHECK(gender='男' OR gender='女'),#检查
    	seat INT UNIQUE,#唯一
    	age INT DEFAULT 18,#默认约束
    	majorId INT REFERENCES major(id)#外键不支持列级约束   majorId INT FOREIGN KEY REFERENCES major(id)
    );
    
    CREATE TABLE major(
    	id INT PRIMARY KEY,
    	majorName VARCHAR(20)
    );
    
    #右击stuinfo,打开表
    
    
    #2.添加表级约束
    /*
    语法:在各个字段的最下面
    【constraint 约束名】 约束类型(被约束的字段名)
    	
    	
    不支持:非空和默认
    */
    DROP TABLE IF EXISTS stuinfo;
    CREATE TABLE stuinfo(
    	id INT,
    	stuname VARCHAR(20),
    	gender CHAR(1),
    	seat INT,
    	age INT,
    	majorid INT,
    	
    	PRIMARY KEY(id),#主键CONSTRAINT pk PRIMARY KEY(id)
    	CONSTRAINT uq UNIQUE(seat),#唯一
    	CONSTRAINT ck CHECK(gender='男' OR gender='女'),#检查
    	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键
    );
    #查看结果
    SHOW INDEX FROM stuinfo;
    
    
    #通用写法
    DROP TABLE IF EXISTS stuinfo;
    CREATE TABLE IF NOT EXISTS stuinfo(
    	id INT PRIMARY KEY,
    	stuname VARCHAR(20) NOT NULL,
    	sex CHAR(1),
    	age INT DEFAULT 18,
    	seat INT UNIQUE,
    	majorid INT,
    	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
    );
    
    
    
    /*
    primary key <----> unique
    
    主键和唯一大PK:
    		保证唯一性	是否允许为空	一个表中可以有多少个		是否允许组合
    primary key      √		    ×		最多1个				允许(不推荐)
    unique		 √		    √		可以多个			允许(不推荐)
    */
    
    #(1)5.6版本的unique,对于约束是unique的字段,插入数据时,只能有一组数据的该字段的值为null
    INSERT INTO major VALUES(1,'java');
    INSERT INTO major VALUES(2,'H5');
    INSERT INTO stuinfo VALUES(1,'join','男',19,NULL,1);
    INSERT INTO stuinfo VALUES(2,'lily','女',19,NULL,2);
    
    SELECT * FROM stuinfo;
    
    #(2)可以为多个字段设置unique,但是只能为一个字段设置primary key
    
    
    #(3)可以设置联合主键
    DROP TABLE IF EXISTS stuinfo;
    CREATE TABLE stuinfo(
    	id INT,
    	stuname VARCHAR(20),
    	gender CHAR(1),
    	age INT,
    	seat INT,
    	majorid INT,
    	
    	PRIMARY KEY(id,stuname),#不是设置两个主键,而是将这两个字段合并成一个字段成为一个主键
    	CONSTRAINT uq UNIQUE(seat),#唯一
    	CONSTRAINT ck CHECK(gender='男' OR gender='女'),#检查
    	CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键
    );
    #不报错
    INSERT INTO stuinfo VALUES(1,'join','男',19,NULL,1);
    INSERT INTO stuinfo VALUES(2,'join','男',19,NULL,2);
    #也不报错
    INSERT INTO stuinfo VALUES(1,'join','男',19,NULL,1);
    INSERT INTO stuinfo VALUES(1,'lily','男',19,NULL,2);
    #报错
    INSERT INTO stuinfo VALUES(1,'join','男',19,NULL,1);
    INSERT INTO stuinfo VALUES(1,'join','男',19,NULL,2);
    
    
    
    /*
    外键:
    	1.要求在从表上设置外键关系
    
    	2.从表的外键列的类型和主表的类型要求一致或兼容,名称无要求
    	
    	3.主表的关联列必须是一个key(一般是主键或唯一键)
    	
    	CREATE TABLE major(
    		id INT PRIMARY KEY,#或者id INT UNIQUE
    		majorName VARCHAR(20)
    	);
    	
    	4.插入数据时,先插入主表major,再插入从表stuinfo
    	
    	5.可以为一个字段加多个约束,往后追加就可以了
    
    
    */
    
    
    
    #二、修改表时添加约束
    /*
    (1)添加列级约束
    alter table 表名 modify column 字段名 字段类型 新约束;
    (2)添加表级约束
    alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;
    */
    
    DROP TABLE IF EXISTS stuinfo;
    CREATE TABLE stuinfo(
    	id INT,
    	stuname VARCHAR(20),
    	gender CHAR(1),
    	seat INT,
    	age INT,
    	majorid INT
    );
    DESC stuinfo;
    
    
    #1.添加非空约束
    ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
    
    
    #2.添加默认约束
    ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
    
    #3.添加主键
    #(1)列级约束
    ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
    #(2)表级约束
    ALTER TABLE stuinfo ADD PRIMARY KEY(id);
    
    
    #4.添加唯一约束
    #(1)列级约束
    ALTER TABLE stuinfo MODIFY COLUMN seat INT UNIQUE;
    #(2)表级约束
    ALTER TABLE stuinfo ADD UNIQUE(seat);
    
    
    #5.添加外键
    #仅表级约束
    ALTER TABLE stuinfo ADD FOREIGN KEY(majorid) REFERENCES major(id);
    #加名字也可以
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major  FOREIGN KEY(majorid) REFERENCES major(id);
    
    
    #三、修改表时删除约束
    #1. 删除非空约束
    ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;
    #或
    ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20);
    
    
    #2.删除默认约束
    ALTER TABLE stuinfo MODIFY COLUMN age INT;
    
    
    #3.删除主键
    ALTER TABLE stuinfo MODIFY COLUMN id INT;
    #或
    ALTER TABLE stuinfo DROP PRIMARY KEY;
    
    
    #4.删除唯一
    ALTER TABLE stuinfo DROP INDEX seat;
    ALTER TABLE stuinfo MODIFY COLUMN seat INT;
    #5.删除外键
    ALTER TABLE stuinfo DROP FOREIGN KEY majorid;
    
    SHOW INDEX FROM stuinfo;
    
    
    案例】
    #【补充】插入数据先插入主表,删除数据先删除从表
    SHOW INDEX FROM major;#有主键
    SHOW INDEX FROM stuinfo;#没有外键
    ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;
    
    #传统方式添加外键
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id);
    
    主表
    SELECT * FROM major;
    #再为major多插入几个数据
    INSERT INTO major
    VALUES(1,'java'),(2,'h5'),(3,'大数据')
    
    
    从表
    SELECT * FROM stuinfo;
    #再为stuinfo多插入几个数据
    INSERT INTO stuinfo
    SELECT 1,'john1','女',NULL,NULL,1 UNION ALL
    SELECT 2,'john2','女',NULL,NULL,1 UNION ALL
    SELECT 3,'john3','女',NULL,NULL,2 UNION ALL
    SELECT 4,'john4','女',NULL,NULL,2 UNION ALL
    SELECT 5,'john5','女',NULL,NULL,1 UNION ALL
    SELECT 6,'john6','女',NULL,NULL,3 UNION ALL
    SELECT 7,'john7','女',NULL,NULL,3 UNION ALL
    SELECT 8,'john8','女',NULL,NULL,1 
    
    
    #删除专业表major的3号专业
    DELETE FROM major WHERE id=3;#报错,因为删除的时候要先删除从表
    #但是如果就想删除呢?该怎么办?
    
    #解决方式1:级联删除
    #先删除原先的外键
    ALTER TABLE stuinfo DROP FOREIGN KEY fk_stu_major;
    #用新方法添加级联删除外键ON DELETE CASCADE
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE CASCADE;
    #删除专业表major的3号专业
    DELETE FROM major WHERE id=3;
    #效果就是:主表major中的3号专业删除了,学员信息表中选择3号专业的学生也删除了
    
    
    
    #解决方式2:级联置空
    #先删除原先的外键
    ALTER TABLE stuinfo DROP FOREIGN KEY fk_stu_major;
    #用新方法添加级联删除外键ON DELETE SET NULL
    ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE SET NULL;
    #删除专业表major的2号专业
    DELETE FROM major WHERE id=2;
    #效果就是:主表major中的2号专业删除了,学员信息表中选择2号专业的学生的majorid的字段变为了null
    
    

    标识列

    #标识列
    /*
    又称:自增长列
    含义:可以不用手动的插入值,系统提供默认的序列值
    
    特点:
    1.标识列不是一定要和主键搭配使用,但是要求是一个key(主键、唯一、外键)
    2.一个表只能有一个标识列
    3.标识列的类型只能是数值型(intfloatdouble等)
    4.标识列可以通过SET auto_increment_increment=3;设置步长,也可以通过手动插入值,设置起始值。
    */
    
    
    #一、创建表时设置标识列
    DROP TABLE IF EXISTS tab_identity;#删除表的所有(字段+数据),删除之后要创建
    
    CREATE TABLE tab_identity(
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	NAME VARCHAR(20)
    );
    
    TRUNCATE TABLE tab_identity;#删除表中所有数据,字段还在,删除之后不用重新创建表,只要重新插入数据
    
    #写法1
    INSERT INTO tab_identity(id,NAME) VALUES(NULL,'john');
    #写法2
    INSERT INTO tab_identity(NAME) VALUES('lucy');
    #写法3
    INSERT INTO tab_identity VALUES(NULL,'lily');
    #错误写法
    INSERT INTO tab_identity VALUES('haha');
    
    #查看
    SELECT * FROM tab_identity;
    
    
    #显示当前自增长列的步长和起始值 (mysql中不支持设置起始值,但是支持设置步长)
    SHOW VARIABLES LIKE '%auto_increment%';
    
    
    #设置步长,一般不建议修改
    SET auto_increment_increment=3;
    
    #虽然不支持通过变量,但是
    INSERT INTO tab_identity(id,NAME) VALUES(10,'john');
    #后面插入的id,全部用null
    
    
    
    #二、修改表时设置标识列
    ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;
    
    #二、修改表时删除标识列
    ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY;
    
  • 相关阅读:
    tp5最强分页 自定义model,控制器引用。只显示一页
    tp5分页,一看就懂,简单明了(附带额外参数)
    PHP 验证5-20位数字加字母的正则(数字和字母缺一不可)!!!
    表格样式
    tp5中很牛皮的一句sql语句,三个条件(两个不确定条件,一个硬性条件)
    centos6.8下搭建git和gitlab版本库
    解决 nginx: [alert] kill(1022, 1) failed (3: No such process)
    Zabbix利用msmtp+mutt发送邮件报警
    nginx基本配置与参数说明
    Linux添加/删除用户和用户组
  • 原文地址:https://www.cnblogs.com/deer-cen/p/12749549.html
Copyright © 2011-2022 走看看