熟悉SQL语法之路!原创精华篇

    学习web安全足足有一个半月有余,之前学的是前端,也会一点python。。好吧差不多忘了。常规工具算是熟悉基本流程了。。还欠缺实战。

    再学习SQL注入的时候,头痛于不理解SQL语法,这个骗不了别人,即使凭借经验记住SQL注入绕过语法也不懂得他们的意思,尤其是看《SQL注入攻击与防御》这本书的150-175页的时候,我是彻底懵比了!  

       我内心是不服输的,然后书一直没看,因为看不懂啊,那种感受就好像有一大堆好吃的在你旁边,你却吸收不了。对就是那种感觉。

    时间就是生命,我这星期才明白什么叫短暂的时间能做出很多事情,时间就像海绵一样,挤一挤就有了。利用下课的空闲时间完成了一份SQL语法笔记,我也是边看W3c边做的笔记。因为住宿,我无法提供数据库练习,这里颇有遗憾,但是笔记理论性绝对强!   笔记不是完美了,我只是个新手,从我的角度从我新手的角度理解,有不对的地方请各位大牛提出来,大家一起互相学习。

   不bb了,看我四天的工作量吧!

熟悉SQL之路

SQL是结构化查询语

SQL对大小写不敏感!

*代表所有!

SELECT获取数据,查询语句

select name(列名) from admin(表名)

————————-

DISINCT,配合SELECT使用,作用,去除重复部分。

select disinct name from admin (from后面是存储数据(列名)的数据库表)

————————-

WHERE字句,SELECT * from person where name=”红尘”  查询列名是红尘的来自person表。

//where是条件语句

用于条件搜索:select * from person where like=’jack’//搜索关键字jack

————————–

AND&OR AND是并列关系,两者都需要满足,OR是或的意思,两者满足其一。

————————–

关于order by

order by字母的排序方式是以:A,B,C,D……Z这种,越靠前就排序靠前。

order by数字的排序方式是以:1,2,3,4,5,6….这种,越靠前排序靠前。

order by字母和order by数字同时排序的时候,排序的方式:字母的排序大于数字的排序!所以排序先看字母,字母越靠前顺序就最前面!假如字母的位数都相同,比较数字的话,那么数字越小的越靠前。

SQL语句对大小写不敏感,ORDER BY也是可以。

反之desc(DESC)是反序排列,排序方法与正序排列雷同。

——————-

insert into语句,含义:像表格中插入新的一行数据

insert into admin(表名) values(‘红尘’,’男’,’red’,’apple’)

*要已知表名是admin并且admin表是四列!

insert into admin(‘姓名’,’性别’) values(‘红尘’,’男’);//指定插入一行数据,你得知道表中的列名。

—————–

update 含义:修改表中的数据

update 表 set(创建) name=jack(新值) where people(列名)=man

update admin set name=jack where people=man

——————

delete语句

delete from admin(表名)  where name(列名)=jack

//删除表中列名为jack的一行。

delete * from table_name

//删除所有行

————-

Top子句,Limit子句,ROWSUM子句

不是所有数据库都支持top字句,支持top的只有mssql数据库(sql server数据库)

top的用法有两种:

1、select top 2  * /  指定某一个列名(columns_name) from admin(表名)  //注释top的含义自我翻译了下,含义很多,感觉最标准就是在…的前头,这里的含义就是查询所有列名中的前两行的数据记录行来自表名 (admin) / 查询前二行的指定列名下的数据内容来自表名(admin)。

2、select top 50percent * / 指定某一个列(columns_name)from admin(表名)   //查询前百分之50的所有列下的数据记录行来自admin(表) / 查询前百分之50的指定列名下的数据来自admin(表)。

///////////////////

与top用法相同的是limit字句,limit适用于mysql,它是支持mysql数据库的。

limit详细用法:

1、select * / 列名(columns_name) from admin(表名) limit 5     //查询前5行的所有列下的数据记录行来自admin(表) / 查询前5行的指定列名下的数据来自admin(表)。2、select * / 列名(columns_name) from admin(表名) limit 5,10 //查询前6行-15行的所有列下的数据记录行来自admin(表) / 查询前5行-15行的指定列名下的数据来自admin(表)。//limit5,10起始是5开始,变成6,因为返回的是所有记录,所以10要加上起始的5就是15。举例:limit 3,6就是前4行-9行。是limit (初始值+1) (初始值+末尾值)使用limit注意点:

limit不可以是负数!limit初始值是0不是1

limt 0相当于limit 0,n。

取决于第二位数。

—————

 与top,limit雷同的语句是:ROWNUM,rownum支持oracle数据库。

用法:select * from admin(表)  where rownum<=5

这里的rownum使用方式比较奇怪,它是跟在where子句上的,是条件语句执行的。

rownum初始值是1,rownum=1就是显示表中的第一行,顾名思义,2就是显示表中的前二行。但是写法上就有点不一样。

假如写成rownum=2,这样写看上去是对的,但是oracle语法不支持这种写法,既然是限制,那么我想显示表中前二行的记录行,那么应该是rownum<=2,这里的意思就是返回前面二行的记录行,<在这里有种过去的意思。

那rownum>2呢,它的意思就是从第二行开始返回记录行。怎么才能使用它?

答:需要调用rownum rn才行!

用法如下:

查询前3条信息:select * from admin where rownum<4

查询前3条信息:select * from admin where rownum<=3

像mssql数据库中top n一样,我们需要:select * from (select * from admin order by ID) where rownum<=5

查询第3条-第5条信息:select * from(select a.* rownum rn from admin(表名) a)  where rn>=3 and rn<=5

a.*是数据库别名,我也不太懂。

————-

LIKE操作符,比较好理解,不像上面的那些好抽象。

用法有四种:

1、select * from admin(表名) where name(列名) like ‘j%’     //查询搜索来自admin表中以j开头name(列名)的人

2、select * from admin(表名) where name(列名) like ‘%j’     //查询搜索来自admin表中以j末尾的name(列名)的人

3、select * from admin(表名) where name(列名) like ‘%jack%’    //查询搜索来自admin表中包含jack的name(列名)的人

4、select * from admin(表名) where name(列名) not like ‘%jack%’    //查询搜索来自admin表中不包含jack的name(列名)的人

—  %是SQL的通配符

————-

IN操作符,选取表中的内容

用法:select * from admin(表) where name(列名) in(‘jack’,’marry’)    //获取来自admin表中的name列名是jack和marry的数据记录行

————

BETWEEN操作符

between..and的含义就是选取两个值之间的数据范围,选取的两个值可以是数字,也可以是字母。

用法:

1、select * from admin where name between ‘jack’ and ‘abc’    //查询来自admin表中列名是在jack和abc之间的数据记录行

2、也可以用大小于号代替BETWEEN

用法如下:select * from admin where number>10 and number<20    //查询来自admin表中number(列名)是在大于10和小于20的之间的数据记录行

这些都是选取两个值之间的数据范围,一切都是两面性,还有不选取两个值之间的数据范围,它就是not between,

not between用法和between用法雷同

———

SQL JOIN彻底刨析

http://blog.jobbole.com/40443/   我已经无法用语言解释了,此乃精品!

———-

SQL  UNION

解释:UNION 指令的目的是将两个 SQL 语句的结果合并起来。从这个角度来看, UNION 跟 JOIN 有些许类似,因为这两个指令都可以由多个表格中撷取资料。 UNION 的一个限制是两个 SQL 语句所产生的栏位需要是同样的资料种类。另外,当我们用 UNION这个指令时,我们只会看到不同的资料值 (类似 SELECT DISTINCT)。不会出现重复的一模一样的。

用法:union select name from admin

//会获取所有的name(列名),不会有重复

————-

SQL  SELECT INTO FROM

———–

熟悉SQL之路续篇1

SQL   SELECT INTO FROM

select…into…from…不支持mysql数据库!

解释三个…;依次从左往后

1、…*/columns_name

2、…newtable_name

3、…oldtable_name

支持mssql数据库!

用法:select id,name into admin2 from admin1      //获取admin1表中的id,name;id和name都是admin1表中的列名插入到admin2表中了。在这里我们不需要事先创建admin2,admin2会系统自动创建假如你事先创建了admin2那么就会说你已经存在此表,不能插入。

—————-

我们也可以添加where子句。

用法:select id,name into admin2 from admin1 where city=’china’   //查询获取来自admin1中的id,name,把id,name插入到admin2表,这个插入过程中,需要满足的条件是要保证插入的城市是china。

———-

create DB 数据库名 //创建数据库

create table 表名称(列名1 数据类型,列名2 数据类型,列名3 数据类型…….)

———

SQL的约束

1、NOT NULL

NOT NULL顾名思义,没有NULL的意思。在SQL语法中就是强制列不接受NULL值。NOT NULL一般写在数据类型的后面或者代替数据类型的位置

举例子说明:

create table abc(

id   int  NOT NULL

);

2、UNIQUE

UNIQUE约束唯一标识数据库表中的每条记录。

UNIQUE 和 PRIMARY KEY 约束均为列或列集合提供了唯一性的保证。

注意点:UNIQUE可以标识多次约束对每个表,而PRIMARY KEY只能标识一次对每个表。

感觉很好理解,不手写了,负责一段内容自己找寻其中规律:

下面的 SQL 在 “Persons” 表创建时在 “Id_P” 列创建 UNIQUE 约束:

     MySQL:

CREATE TABLE Persons ( Id_P int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), UNIQUE (Id_P) )

     SQL Server / Oracle / MS Access:

CREATE TABLE Persons ( Id_P int NOT NULL UNIQUE, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255) )

     如果需要命名 UNIQUE 约束,以及为多个列定义 UNIQUE 约束,请使用下面的 SQL 语法:

     MySQL / SQL Server / Oracle / MS Access:

CREATE TABLE Persons ( Id_P int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), CONSTRAINT uc_PersonID UNIQUE (Id_P,LastName) )

——-

规律:UNIQUE约束都是添加在最后的,约束一个的话,最后一个逗号是UNIQUE前面一位数据类型上,而且需要区别数据库。UNIQUE约束多位的话,不需要区分多位数据库,并且UNIQUE约束的前一位数据类型后面不需要逗号,数据库认为约束的前面一位是最后一位。

3、PRIMARY KEY

不想手写了,参照UNIQUE就行!摘录网上的一段:

SQL PRIMARY KEY 约束

     PRIMARY KEY 约束唯一标识数据库表中的每条记录。

     主键必须包含唯一的值。

     主键列不能包含 NULL 值。

     每个表都应该有一个主键,并且每个表只能有一个主键。

SQL PRIMARY KEY Constraint on CREATE TABLE

     下面的 SQL 在 “Persons” 表创建时在 “Id_P” 列创建 PRIMARY KEY 约束:

     MySQL:

CREATE TABLE Persons ( Id_P int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), PRIMARY KEY (Id_P) )

     SQL Server / Oracle / MS Access:

CREATE TABLE Persons ( Id_P int NOT NULL PRIMARY KEY, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255) )

     如果需要命名 PRIMARY KEY 约束,以及为多个列定义 PRIMARY KEY 约束,请使用下面的 SQL 语法:

     MySQL / SQL Server / Oracle / MS Access:

CREATE TABLE Persons ( Id_P int NOT NULL, LastName varchar(255) NOT NULL, FirstName varchar(255), Address varchar(255), City varchar(255), CONSTRAINT pk_PersonID PRIMARY KEY (Id_P,LastName) )

//自行寻找规律

4、FOREIGN KEY

FOREIGN KEY的含义是外键。

看了文章没看懂,到时候看懂补上。。。

为什么要添加外键?

答:FOREIGN KEY 约束用于预防破坏表之间连接的动作。

FOREIGN KEY 约束也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一。

熟悉SQL之路续篇2

5、SQL CHECK 约束  挺简单的。。。。

CHECK 约束用于限制列中的值的范围。

如果对单个列定义 CHECK 约束,那么该列只允许特定的值。

如果对一个表定义 CHECK 约束,那么此约束会在特定的列中对值进行限制。

SQL CHECK Constraint on CREATE TABLE

下面的 SQL 在 “Persons” 表创建时为 “Id_P” 列创建 CHECK 约束。CHECK 约束规定 “Id_P” 列必须只包含大于 0 的整数。

My SQL:

CREATE TABLE Persons

(

Id_P int NOT NULL,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255),

CHECK (Id_P>0)

)

SQL Server / Oracle / MS Access:

CREATE TABLE Persons

(

Id_P int NOT NULL CHECK (Id_P>0),

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255)

)

如果需要命名 CHECK 约束,以及为多个列定义 CHECK 约束,请使用下面的 SQL 语法:

MySQL / SQL Server / Oracle / MS Access:

CREATE TABLE Persons

(

Id_P int NOT NULL,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255),

CONSTRAINT chk_Person CHECK (Id_P>0 AND City=’Sandnes’)

)

SQL CHECK Constraint on ALTER TABLE

如果在表已存在的情况下为 “Id_P” 列创建 CHECK 约束,请使用下面的 SQL:

MySQL / SQL Server / Oracle / MS Access:

ALTER TABLE Persons

ADD CHECK (Id_P>0)

如果需要命名 CHECK 约束,以及为多个列定义 CHECK 约束,请使用下面的 SQL 语法:

MySQL / SQL Server / Oracle / MS Access:

ALTER TABLE Persons

ADD CONSTRAINT chk_Person CHECK (Id_P>0 AND City=’Sandnes’)

撤销 CHECK 约束

如需撤销 CHECK 约束,请使用下面的 SQL:

SQL Server / Oracle / MS Access:

ALTER TABLE Persons

DROP CONSTRAINT chk_Person

MySQL:

ALTER TABLE Persons

DROP CHECK chk_Person

//偷懒了,实在内容太多这块,我解释不清。。。但是这个没啥难度。

6、DEFAULT

SQL DEFAULT 约束

DEFAULT 约束用于向列中插入默认值。

如果没有规定其他的值,那么会将默认值添加到所有的新记录。

SQL DEFAULT Constraint on CREATE TABLE

下面的 SQL 在 “Persons” 表创建时为 “City” 列创建 DEFAULT 约束:

My SQL / SQL Server / Oracle / MS Access:

CREATE TABLE Persons

(

Id_P int NOT NULL,

LastName varchar(255) NOT NULL,

FirstName varchar(255),

Address varchar(255),

City varchar(255) DEFAULT ‘Sandnes’

)

通过使用类似 GETDATE() 这样的函数,DEFAULT 约束也可以用于插入系统值:

CREATE TABLE Orders

(

Id_O int NOT NULL,

OrderNo int NOT NULL,

Id_P int,

OrderDate date DEFAULT GETDATE()

)

SQL DEFAULT Constraint on ALTER TABLE

如果在表已存在的情况下为 “City” 列创建 DEFAULT 约束,请使用下面的 SQL:

MySQL:

ALTER TABLE Persons

ALTER City SET DEFAULT ‘SANDNES’

SQL Server / Oracle / MS Access:

ALTER TABLE Persons

ALTER COLUMN City SET DEFAULT ‘SANDNES’

撤销 DEFAULT 约束

如需撤销 DEFAULT 约束,请使用下面的 SQL:

MySQL:

ALTER TABLE Personsk

ALTER City DROP DEFAULT

SQL Server / Oracle / MS Access:

ALTER TABLE Persons

ALTER COLUMN City DROP DEFAULT

—————-

CREATE  INDEX

create index index_name on table_name (column_name)

//”column_name” 规定需要索引的列。

————-

SQL删除索引,表和数据库。

通过使用 DROP 语句,可以轻松地删除索引、表和数据库。

SQL DROP INDEX 语句

我们可以使用 DROP INDEX 命令删除表格中的索引。

用于 Microsoft SQLJet (以及 Microsoft Access) 的语法:

DROP INDEX index_name ON table_name

用于 MS SQL Server 的语法:

DROP INDEX table_name.index_name

用于 IBM DB2 和 Oracle 语法:

DROP INDEX index_name

用于 MySQL 的语法:

ALTER TABLE table_name DROP INDEX index_name

SQL DROP TABLE 语句

DROP TABLE 语句用于删除表(表的结构、属性以及索引也会被删除):

DROP TABLE 表名称

SQL DROP DATABASE 语句

DROP DATABASE 语句用于删除数据库:

DROP DATABASE 数据库名称

SQL TRUNCATE TABLE 语句

如果我们仅仅需要除去表内的数据,但并不删除表本身,那么我们该如何做呢?

请使用 TRUNCATE TABLE 命令(仅仅删除表格中的数据):

TRUNCATE TABLE 表名称

———————————

SQL  ALERT TABLE

ALTER TABLE 语句

ALTER TABLE 语句用于在已有的表中添加、修改或删除列。

SQL ALTER TABLE 语法

如需在表中添加列,请使用下列语法:

ALTER TABLE table_name(表名)

ADD column_name(列名) datatype(数据类型)

要删除表中的列,请使用下列语法:

ALTER TABLE table_name

DROP COLUMN column_name(列名)

改变数据类型实例

我们使用下列 SQL 语句:

ALTER TABLE admin(表名)

ALTER COLUMN Birthday year(数据类型)

//修改表名中的列名的数据类型,把原先的数据类型改成year数据类型。

删除admin表中的列名Birthday

SQL语法如下:ALTER TABLE admin DROP COLUMN Birthday

——————-

SQL AUTO INCREMENT

AUTO INCREMENT 字段

我们通常希望在每次插入新记录时,自动地创建主键字段的值。

我们可以在表中创建一个 auto-increment 字段。

  自己的理解:就是主键的排序方式以递增的方式,是以1,2,3,4….这种,不是那种凌乱零散的排序,AUTO INCREMENT的开始值是1,以1递增。

——————

熟悉SQL之路续篇3

1、SQL NULL

NULL 值是遗漏的未知数据。

SQL NULL 值

如果表中的某个列是可选的,那么我们可以在不向该列添加值的情况下插入新记录或更新已有的记录。这意味着该字段将以 NULL 值保存。

NULL 值的处理方式与其他值不同。

NULL 用作未知的或不适用的值的占位符。

注释:无法比较 NULL 和 0;它们是不等价的。

SQL 的 NULL 值处理

请看下面的 “Persons” 表:

Id LastName FirstName Address City

1 Adams         John                     London

2 Bush George Fifth Avenue     New York

3 Carter   Thomas                        Beijing

假如 “Persons” 表中的 “Address” 列是可选的。这意味着如果在 “Address” 列插入一条不带值的记录,”Address” 列会使用 NULL 值保存。

那么我们如何测试 NULL 值呢?

无法使用比较运算符来测试 NULL 值,比如 =, <, 或者 <>。

我们必须使用 IS NULL 和 IS NOT NULL 操作符。

———-

2、SQL IS NULL

我们如何仅仅选取在 “Address” 列中带有 NULL 值的记录呢?

我们必须使用 IS NULL 操作符:

SELECT LastName,FirstName,Address FROM Persons

WHERE Address IS NULL

结果集:

LastName FirstName Address

Adams John

Carter Thomas

提示:请始终使用 IS NULL 来查找 NULL 值。

———

3、SQL IS NOT NULL

我们如何选取在 “Address” 列中不带有 NULL 值的记录呢?

我们必须使用 IS NOT NULL 操作符:

SELECT LastName,FirstName,Address FROM Persons  WHERE Address IS NOT NULL

结果集:

LastName FirstName Address

Bush George Fifth Avenue

源于W3C,这个解释的比较清楚,感觉没啥难度。

————

SQL NULL函数

不解释了:http://www.w3school.com.cn/sql/sql_isnull.asp    自己去看,我解释不了。

SQL关键之SQL函数

SQL SVG()   此函数用来计算数值列的平均值,NULL不包括在其中。

用法:select SVG(column_name) from table_name

———-

SQL COUNT()   此函数用来返回匹配指定条件的行数。

用法:select COUNT(column_name) from table_name

实例:

1、select COUNT(name) from admin      //查询来自admin表中的的列名name总共有多少行,假如name中有重复的名字,那么想不重复,语法如下:select COUNT(DISTINCT name) from admin //查询来自admin表中的列名是name的行数,name不重复。

2、select COUNT(*) from admin   //查询并且返回admin表中的全部行数,*代表所有,你懂的。

———-

3、SQL FIRST()    FIRST() 函数返回指定的字段中第一个记录的值。

用法:select FIRST(column_name) from table_name

———–

4、SQL LAST()    LAST() 函数返回指定的字段中最后一个记录的值。

用法:select LAST(column_name) from table_name

————–

5、SQL MAX()

MAX()函数返回一列中的最大值。NULL 值不包括在计算中。

用法:select MAX(column_name) from table_name

—————

6、SQL MIN()

MIN() 函数

MIN函数返回一列中的最小值。NULL 值不包括在计算中。

用法:select MIN(column_name) from table_name

———–

7、SQL SUM() 函数

SUM()函数返回数值列的总数(总额)。

用法:select SUM(column_name) from table_name

————

8、SQL GROUP BY子句

GROUP BY 语句用于结合合计函数(如SUM就是合计函数),根据一个或多个列对结果集进行分组。

用法:select name(列名),SUM(money(列名)) from admin(表名) GROUP BY name

注意点:当name列中有相同的名字的话,那么group by的时候两个名字自动合并成一个名字。

——–

9、SQL HAVING子句

代替where子句,用法雷同于where。

看看w3c给的解释:在 SQL 中增加 HAVING 子句原因是,WHERE 关键字无法与合计函数一起使用。

用法:select name(列名),SUM(money(列名)) from admin(表) GROUP BY name(列名) HAVING  SUM(money(列名))<1500  //查询来自admin表中的名字和money的总和把他们的结果进行分组,有相同的就合并条件是name中money的总和要大于1500。

深度理解:group by是对你的结果进行分组,而having是对查询的结果进行一定的筛选。where只是一个普通的条件句,它只针对一些简单的条件进行的查询!

having子句与where子句的区别是:where子句在分组之前过滤数据,而having子句则过滤分组后的数据,从这两个示例来讲,后面这个的性能会比较前面的高。

————–

10、SQL  UCASE() 函数

UCASE()函数把字段的值转换为大写。

用法:select UCASE(column_name) from table_name

————–

11、SQL LCASE()函数

LCASE()函数把字段的值转换成小写。

用法:select LCASE(column_name) from table_name

————-

12、MID() 函数

MID()函数用于从文本字段中提取字符。

SQL MID() 语法

select MID(column_name,start,[length]) from table_name

参数 描述

column_name 必需。要提取字符的字段。

start 必需。规定开始位置(起始值是 1)。

length 可选。要返回的字符数。如果省略,则 MID() 函数返回剩余文本。

用法:select MID(name,1,3) from admin

//查询来自admin表中的列名并且提取name(列名)中的前三个数。

———–

12、SQL LEN()

LEN()函数返回文本字段中值的长度。

用法:select LEN(column_name) from table_name

———–

13、SQL ROUND()

ROUND()函数用于把数值字段舍入为指定的小数位数。

SQL ROUND() 语法

SELECT ROUND(column_name,decimals) FROM table_name

参数 描述

column_name 必需。要舍入的字段。

decimals 必需。规定要返回的小数位数。

用法:select ROUND(price,1) from admin

//查询来自admin表中的价格,因为有ROUND函数,所以对price列的数据进行四舍五入并且保留一位小数,假如是ROUND(price,0),那么就是不保留小数。

———–

14、SQL NOW()

NOW()函数返回当前的日期和时间。

用法:select NOW() from table_name

————

15、SQL FORMAT()

FORMAT 函数用于对字段的显示进行格式化。

SQL FORMAT() 语法

SELECT FORMAT(column_name,format) FROM table_name

参数

描述

column_name

必需。要格式化的字段。

format

必需。规定格式。

—–

举实例方便理解:select FORMAT(name,’jack’) from admin

//name是列名,admin是表名,FORMAT是格式化函数,这句话含义:查询来自admin表中的name列名,因为启用了FORMAT函数,所以格式化name列名中的jack。

      好了,笔记完了,利用了一点空闲时间写的,其实人的潜力还是很大的,赶快加入我吧,努力学习,珍惜你的时间。

    原文作者:一叶红尘哦哟
    原文地址: https://www.jianshu.com/p/bdf8551d190d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞