第3章关系数据库标准语言SQL

第3章关系数据库标准语言SQL


本文全部内容来自数据库系统概论(第5版)—王珊、萨师煊著


3.1SQL概述

  • 综合统一
  • 高度非过程化
  • 面向集合的操作方式
  • 以同一种语法结构提供多种使用方式
  • 语法简洁,易学易用
SQL功能动词
数据查询SELECT
数据定义CREATE、DROP、ALTER
数据操纵INSERT、UPDATE、DELETE
数据控制GRANT、REVOKE

基本概念:

3.2 学生—课程数据库

学生表:Student(Sno,Sname,Ssex,Sage,Sdept)
课程表:Course(Cno,Cname,Cpno,Ccredit)
学生选课表:SC(Sno,Cno,Grade)
学号Sno姓名Sname性别Ssex年龄Sage所在系Sdept
201215121李勇20CS
201215122刘晨19CS
201215123王敏20MA
201215125张立19IS
课程号Cno课程名Cname先行课Cpno学分Ccredit
1数据库54
2数学2
3信息系统14
4操作系统63
5数据结构74
6数据处理2
7PASCAL语言64
学号Sno课程号Cno成绩Grade
201215121192
201215121286
201215121389
201215122290
201215122380
201215123380

3.3 数据定义

操作对象创建删除修改
模式CREATE SCHEMADROP SCHEMA
CREATE TABLEDROP TABLEALTER TABLE
视图CREATE VIEWDROP VIEW
索引CREATE INDEXDROP INDEXALTER INDEX

一个关系数据库管理系统的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象。

3.3.1模式的定义和删除

1、定义模式

CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;

创建模式一般需要获得管理员权限。

用户在创建模式的同时,也可以创建表(TABLE)、视图(VIEW),定义授权。

CREATE SCHEMA <模式名> AUTHORIZATION <用户名> [<表定义子句>|<视图定义子句>|<授权定义子句>];

/*#实例*/
CREATE SCHEMA TEST AUTHORIZATION ZHANG
CREATE TABLE TAB1(COL1 SMALLINT,
                 COL2 INT,
                 COL3 CHAR(20),
                 COL4 NUMERIC(10,3),
                 COL5 DECIMAL(5,2));

2、删除模式

DROP SCHEMA <模式名><CASCADE|RESTRICT>;
  • CASCADE:级联,表示在删除模式时,把该模式中所有的数据库对象都删除。
  • RESTRICT:限制,表示如果有定义的下属数据库对象,拒绝该删除语句的执行。
DROP SCHEMA ZHANG CASCADE;
/*#删除模式的同时,将定义的表也删除了*/

3.3.2 基本表的定义、删除与修改

1、定义基本表

CREATE TABLE <表名>(<列名> <数据类型> <完整性约束条件>,
                 	...,
                  	...
                 );
/*实例*/
CREATE TABLE TAB1(COL1 SMALLINT,
                 COL2 INT,
                 COL3 CHAR(20),
                 COL4 NUMERIC(10,3),
                 COL5 DECIMAL(5,2));

在建表的同时一定要定义完整性约束条件。

/*实例:建立一个学生信息表*/
CREATE TABLE Student(
	Sno CHAR(10) PRIMARY KEY,	/*PRIMARY KEY 主键参数,使Sno是可以识别学生的唯一对象*/
    Sname CHAR(20) UNIQUE,		/*UNIQUE 参数,表示学生姓名具有唯一性*/
    Ssex CHAR(2),
    Sage SMALLINT,
    Sdept CHAR(20),
);
/*实例:建立一个课程表*/
CREATE TABLE Course(
	Cno char(4) primary key,
    Cname char(20) not null,
    Cpno char(4),
    Ccredit int,
    foreign key (Cpno) references Course(Cno)    /*表级完整性约束*/
);
/*实例:建立一个学生选课表*/
CREATE TABLE SC(
	Sno char(10),
    Cno char(4),
    Grade int,
    primary key(Sno,Cno),
    foreign key(Sno) references Student(Sno),
    foreign key(Cno) references Course(Cno)
);

2、数据类型

数据类型含义
char(n)长度为n的定长字符串
varchar(n)长度为n的变长字符串
int,integer长整数
DATE日期,包含年、月、日,格式为YYYY-MM-DD
TIME时间,包含一日的时、分、秒,格式为HH:MM:SS

3、模式与表

每个基本表都属于某一个模式,一个模式可以包含多个基本表。

支持在创建表的同时创建模式。

4、修改基本表

ALTER TABLE <表名>
/*实例:添加入学时间列,数据类型为日期型*/
ALTER TABLE Student ADD S_entrance DATE;
/*实例:将年龄的数据类型由字符型改为整数*/
ALTER TABLE Student ALTER COLUMN Sage INT;
/*实例:为课程名称增加必须取唯一值的约束条件*/
ALTER TABLE Course ADD UNIQUE(Cname);
  • ADD语句,用于增加新列,新的列级完整性约束条件和新的表级完整性约束条件
  • DROP COLUMN语句,用于删除表中的列
  • DROP CONSTRAINT语句,用于删除指定的完整性约束条件
  • ALTER COLUMN语句,用于修改原有的列定义,包括修改列名和数据类型

5、删除基本表

DROP TABLE <表名> RESTRICT|CASCADE;

默认情况下,删除表时,由于存在限制条件而不被允许。默认值为RESTRICT

3.3.3 索引的建立与删除

建立索引是加快查询速度的有效手段。

  • 顺序文件上的索引
  • B+树索引
  • 散列索引
  • 位图索引

1、建立索引

CREATE UNIQU|CLUSTER INDEX <索引名> ON <表名>;

索引值的建立可以指定排列次序,默认为ASC(升序),还可选DESC(降序)

  • UNIQUE:表示此索引的每一个索引值只对应唯一的数据记录
  • CLUSTER:表示要建立的索引时聚簇索引

2、修改索引

ALTER INDEX <旧索引名> RENAME TO <新索引名>;

3、删除索引

DROP index <索引名>;

在索引建立成功之后,系统会自动使用和维护。当频繁使用增删改时,应该删除不必要的索引,避免发生查询效率不高的情况。

3.3.4 数据字典

数据字典是关系数据库管理系统内部的一组系统表,它记录了数据库中所有的定义信息,包括关系模式定义、视图定义、索引定义、完整性约束定义、各类用户对数据库的操作权限、统计信息等。

3.4 数据查询

数据查询是数据库的核心操作。

SELECT (ALL|DISTINCT) <目标表达式>
FROM <表名或视图名>
WHERE <条件表达式>
GROUP BY <列名1> (HAVING<>)
ORDER BY <列名2> (ASC|DESC);

根据WHERE子句的表达式从FROM子句指定的基本表、视图或派生表中找出满足条件的元组,再按SELECT子句中的目标表达式选出元组中的属性值形成结果表。

3.4.1 单表查询

1、选择表中的若干列

选择表中的全部或部分列进行关系代数的投影运算。

  • 查询指定列

    SELECT Sno,Sname FROM Student;
    /*属性名的顺序决定输出结果的顺序*/
    
  • 查询所有列

    select * from Student;
    /* *号表示所有的列名都输出  */
    
  • 查询经过计算的值

    /*查询出生年月*/
    select Sname,2014-age from Student;
    /* 目标列的表达式也可以是表达式,不仅可以是算术表达式,也可以是字符串常量、函数等 */
    
    • 用户还可以指定列名为其他的别名,用来替代需要计算得出的结果

      select Sname,'year of brith:',2014-age birthday,lower(Sdept) from Student;
      /*单引号内的内容不会被解析,别名的使用直接添加在列名的后面即可*/
      

2、选择表中的若干元组

  • 消除取值的重复行

    /* 使用distinct可以删除查询结果中的重复行 */
    select distinct Sno from SC;
    /* 指定默认值为all,保留所有信息*/
    
  • 查询满足条件的元组

    /* 指定的条件需要使用where子句来实现 */
    select Sname from Student where Sdept='CS';
    
    查询条件谓词
    比较=,>=,<=,!=,所有的比较运算符都可以使用
    确定范围between and,not between and
    确定集合in,not in
    字符匹配like ,not like
    空值is null ,is not null
    多重条件and,or,not
    • 确定范围:between后是范围的下限,and后是范围的上限
    • 字符匹配:%代表任意长度的字符串,_代表任意单个字符,查询中如果存在%_需要使用escape进行转义

3、order by 语句

用户可以使用order by语句对查询结果按照一个或多个属性列的升序(ASC)和降序(DESC)排列,默认值为升序(ASC

/*单个属性列排序*/
select Sno,Grade from SC where Cno='3' order by Grade desc;
/*多个属性列使用不同的方式排序*/
select * from Student order by Sno asc,Sage desc;

空值排序是的显示次序有具体系统实现决定的。

4、聚集函数

count(*)		/*统计元组个数*/
count(<列名>)		/*统计一列中值得个数*/
sum(<列名>)		/*计算一列值的总和*/
avg(<列名>)		/*计算一列值的平均值*/
max(<列名>)		/*计算一列值的最大值*/
min(<列名>)		/*计算一列值的最小值*/

聚集函数中,只有 count(*)会对空值进行处理。

where语句中不能使用聚集函数作为表达式,聚集函数只能在select语句和group by中的having语句

5、group by 语句

用户可以使用group by 语句将查询结果按某一列或多列的值分组,值相等的为一组。

/*查询选修了三门以上课程的学生学号*/
select Sno from SC group by Sno having count(*)>3;

3.4.2 连接查询

连接查询是关系数据库中最主要的查询。

1、等值与非等值连接

select Student.*,SC.* from Student,SC where Student.Sno = SC.Sno;
/* 将Student和SC中同一学生连接起来*/

在等值连接中把目标列中重复的属性列去掉则为自然连接

select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade from Student,SC where Student.Sno=SC.Sno;
/*由于Sno是外键,因此引用是必须加上表名前缀*/

where语句可以使用复合语句同时完成连接和查询的功能。

select Student.Sno,Sname from Student,SC where Student.Sno=SC.Sno and SC.Cno='2' and SC.Grade>90;

2、自身连接

一个表与其子集进行连接。

/*查询每一门课的间接先修课*/
select first.Cno,second.Cpno from Course first,Course second where first.Cpno=second.Cno;

/*由于是自身连接,因此表名容易混淆,所以采用取别名来标记两次使用的表*/

3、外连接

在连接操作中,只有满足连接条件的元组才能作为结果输出。因此,一般采用外连接的方式,将一些悬浮元组的结果显示出来。

select Student.Sno,Sname,Ssex,Sage,Sdept,Cno,Grade 
from Student left outer join SC on (Student.Sno=SC.Sno);

左外连接是列出左边关系中所有的元组,右外连接时列出右边关系中所有的元组。

4、多表连接

连接两个以上的表是多表连接。

select Student.Sno,Sname,Cname,Grade
from Student,SC,Course
where Student.Sno=SC.Sno and SC.Cno=Course.Cno;

在执行多表查询时,先将两个表进行连接,在将第三个表连接。

3.4.3 嵌套查询

一个 select-from-where语句成为一个查询块,将一个查询块嵌套在另一个查询块的 where或者 having语句的条件中,称为嵌套查询。

select Sname from Student where Sno in		/*外层查询或父查询*/
(select Sno from SC where Cno='2');			/*内层查询或子查询*/

1、带有in谓词的子查询

在嵌套查询中,子查询的结果往往是一个集合。

/*查询与“刘晨”在一个系学习的学生*/
select Sno,Sname,Sdept from Student where Sdept in
(select Sdept from Student where Sname='刘晨');

/*如果不适用嵌套查询,应该是使用两步查询*/
/*第一步查询“刘晨”所在系名,第二步查询所有与“刘晨”同系的学生*/

不相关子查询:子查询的查询条件不依赖于父查询。

相关子查询:子查询的查询条件依赖于父查询

2、带有比较运算符的子查询

父查询与子查询之间用比较运算符进行连接。

/*查询与“刘晨”在一个系学习的学生,采用比较运算符的形式*/
select Sno,Sname,Sdept from Student where Sdept =
(select Sdept from Student where Sname='刘晨');
/*找出每个学生超过它子集选修课程平均成绩的课程号*/
select Sno,Cno from SC x where Crade >= 
(select avg(Grade) from SC y where y.Sno=x.Sno);

此例就是一个相关子查询,参数x.Sno的值与父查询有关。

3、带有any或all的子查询

使用any或all时,必须使用比较运算符。

  • any:代表查询结果中的某个值
  • all:代表查询结果中的所有值
/*查询非计算机科学系中比计算机科学系任意一个学生年龄小的学生姓名和年龄*/
select Sname,Sage from Student where Sage<any(
	select Sage from Student where Sdept='CS'
) and Sdept <> 'CS';
/*一个圆括号()代表一个查询*/

所有的查询都可以采用不同的方式来进行,不同的方法其执行效率可能会有差别。因此数据库编程人员应该掌握数据库性能调优技术。

4、带有EXISTS的子查询

存在量词EXISTS和NOT EXISTS,进行查询后结果不会返回任何数据,只产生逻辑真和逻辑假 TRUE or FALSE

  • EXISTS:当内层循环返回非空时,则外层where子句返回真,否则返回假。

  • NOT EXISTS:当内层查询结果为空时,则外层where语句返回真,否则返回假。

/*查询所有选修了1号课程的学生姓名*/
select Sname from Student where exists(
	select * from SC where Sno=Student.Sno and Cno='1'
);
/*若内层查询结果非空,则外层的where子句返回真值,否则返回假值*/

由EXISTS引出的子查询,其目标列表达式通常都用*表示,给出实际列名无意义。

使用IN谓词、比较运算符、ANY、ALL谓词的子查询都能用带EXISTS谓词的子查询代替。

/*查询与“刘晨”在一个系学习的学生*/
select Sno,Sname,Sdept from Student S1 where EXISTS
(select * from Student S2 where S2.Sdept=S1.Sdept and S2.Sname='刘晨');

没有全称量词,因此把使用全程量词的谓词转换成等价的带有存在量词的谓词

/*查询选修全部课程的学生*/
select Sname from Student where not exists (
	select * from Course where not exists (
    	select * from SC where Sno=Student.Sno and Cno=Course.Cno
    )
);

还可以使用逻辑蕴涵来表达,例如要查询至少选修了学生201212122选修的全部课程的学生号码

/*查询学校为x的学生,对所有的课程y,只要201215122学生选修了课程y,则x也选修了y*/
select distinct Sno from SC SCX where not exists (
	select * from SC SCY where SCY.Sno='201215122' and not exists(
    	select * from SC SCZ where SCZ.Sno=SCX.Sno and SCZ.Cno=SCY.Cno
    )
);

3.4.4 集合查询

集合操作主要包括并操作UNION(逻辑运算or)、交操作INTERSECT(逻辑运算and)、差操作EXCEPT

参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同。

例:查询计算机科学系的学生及年龄不大于19岁的学生

select * from Student where Sdept='CS' union 
select * from Student where Sage<=19;

select * from Student where Sdept='CS' or Sage<=19;

例:查询选修了课程1或者课程2的学生

select Sno from SC where Cno='1' union
select Sno from SC where Cno='2';

例:查询计算机科学系中年龄不大于19岁的学生

select * from Student where Sdept="CS" intersect
select * from Student where Sage<=19;

select * from Student where Sdept='CS' and Sage<=19;

例:查询既选修了课程1又选修了课程2 的学生

select Sno from SC where Cno='1' intersect
select Sno from SC where Cno='2';

select Sno from SC where Cno='1' and Sno in(
    select Sno from SC where Cno='2'
);

例:查询计算机科学系的学生与年龄不大于19岁的学生的差集

select * from Student where Sdept='CS' except
select * from Student where Sage<=19;

select * from Student where Sdept='CS' and Sage>=19;

3.4.5 基于派生表的查询

子查询不仅可以出现在where子句中,还可以出现在from子句中,这是子查询生成的临时派生表成为主查询的查询对象。

select Sname from Student,
(select Sno from SC where Cno='1') as SC1
where Student.Sno=SC1.Sno;

通过from语句生成派生表时,as关键字可以省略,但是必须为派生表指定一个别名。

3.4.6 select语句的一般格式

select语句的一般格式:

select all|distinct <目标表达式>
from <表名或视图名>
where <条件表达式>
group by <列名1>
order by <列名2>

1、目标表达式的可选模式

  • *:代表所有的列名
  • <表名>.*
  • count(distinct|all *)
  • <表名>.<属性列名表达式>

2、聚集函数的一般格式

  • count

  • sum

  • avg

  • max

  • min

    distinct|All<列名>

3、where子句表达式的可选格式

3.5数据更新

数据的更新操作有三种:向表中添加若干行数据、修改表中的数据和删除表中的若干行数据

3.5.1 插入数据

插入语句使用insert,一种是插入一个元组,另一种是插入子查询结果。

1、插入元组

insert into <表名> values (<常量1>,<常量2>);

如果into子句中没有指定任何属性列,则新插入的元组必须在每个属性列上均有值。

例:将一个新学生元组(学号:201215128,姓名:陈东,性别:男,所在系:IS,年龄:18岁)插入Student表中。

insert into Student(Sno,Sname,Ssex,Sdept,Sage)
values('201215128','陈东','男','IS',18);

在对新元组进行赋值时,使用单引号括起来。

例:直接插入信息,将学生张成名的信息添加到学生表中。

insert into Student
values('201215126','张成名','男',19,'CS');

在不指定属性名的时候,一定要按照定义表的属性名的顺序进行排序,将属性列的信息添加到表中。

例:添加一条选课记录(‘201015128’,‘1’)

insert into SC(Sno,Cno) values('201215128','1');

某些属性名在不添加值的时候系统会将其设定为默认值,用户也可以自动添加NULL空值。

values语句中也可以添加多个元组信息,用来一次性向表中添加多条元素,但是一定要注意格式的书写。

2、插入子查询结果

插入子查询结果的格式为:

insert into <表名>
/*子查询*/;

例:先创建一个表,在对学生求平均年龄,并把结果存入数据库中

create table dept_age(Sdept char(15) ave_age int);
insert into dept_age(Sdept,ave_age) 
select Sdept,avg(Sage) from Student group by Sdept;

3.5.2 修改数据

修改操作又称更新操作

update <表名> set <列名>=<表达式>,<列名>=<表达式> where <条件>;

修改指定表中满足where语句条件的元组,其中set语句给出表达式的值用于取代相应的属性列值。如果省略where子句,则表示要修改表中的所有元组。

1、修改某一元组的值

例:将学生201215121的年龄改为22岁

update Student set Sage=22 where Sno='201215121';

2、修改多个元组的值

例:将所有学生的年龄增加1岁

update Student set Sage=Sage+1;

3、带子查询的修改语句

在update语句中也可以嵌套子查询语句

例:将计算机科学系全体学生的成绩置零

update SC set Grade=0 where Sno in(
	select Sno from Student where Sdept='CS'
);

3.5.3 删除数据

删除数据的一般格式为:

delete from <表名> where <条件表达式>;

delete语句是删除表中所有满足where语句条件的所有元组,所以说delete语句删除的是数据,而不是表的定义。

1、删除某一个元组的值

例:删除学号为201215128的学生记录

delete from Student where Sno='201215128';

2、删除多个元组的值

例:删除所有学生的选课记录

delete from SC;

3、带子查询的删除语句

例:删除计算机科学系所有学生的选课记录

delete from SC where Sno in (
	select Sno from Student where Sdept='CS'
);

3.6 空值的处理

所谓空值就是“不知道”或“不存在”或“无意义”的值。对于空值需要进行特殊的处理,因为空值具有不确定性,对关系运算会带来特殊的问题。

1、空值的产生

  • 用户插入数据时会产生
  • 用户在修改数据时产生
  • 外连接时

2、空值的判断

判断一个属性是否为空值,用is nullis not null

例:从学生表中找出漏填的学生信息

select * from Student where 
Sname is null or Ssex is null or Sage is null or Sdept is null; 

3、空值的约束条件

  • 属性定义时有not null约束条件的不能取空值

  • 加了unique限制的属性不能取空值

  • 码属性也不能取空值

4、空值的算数运算、比较运算和逻辑运算

例:选出选修课程为1号的不及格的学生以及缺考的学生

select Sno from SC where Grade<60 and Cno='1'
union
select Sno from SC where Grade is null and Cno='1';

select Sno from SC where Cno='1' and (Grade < 60 or Grade is null);

空值与真值,假值进行运算时:

  • 算数运算:空值与另一个值(包括空值)的算数运算结果为空值

  • 比较运算:空值与另一个值(包括空值)的比较运算结果为不确定值

  • 逻辑运算:由于添加了不确定值,因此逻辑运算变成了三值逻辑运算。

    XYX AND Y(乘法)X OR Y(加法)NOT X
    TTTTF
    TUUTF
    TFFTF
    UTUTU
    UUUUU
    UFFUU
    FTFTT
    FUFUT
    FFFFT

    将真值比作1,假值比作0,and运算看成乘法运算,or运算看成加法运算。

3.7 视图

视图是从一个或几个基本表中(或视图)导出的表。它是一个虚表,数据库中只存放视图的定义,不存放视图对应的数据。一旦基本表的数据发生变化时,从视图查询出的数据也相应改变啦。

3.7.1 定义视图

1、建立视图

create view 视图名 (列名,列名)
as 子查询
with check option;

子查询可以使任意的select语句。

with check option语句会将子查询的条件语句,在用户对视图进行更新、插入、删除时保证更新。

组成视图的属性列名或者全部省略或者全部指定,以下三种情况必须指定组成视图的所有列名:

  • 某个目标列不是单纯的属性名,而是聚集函数或列表达式
  • 多表连接时选出了几个同名列作为视图的字段
  • 需要在视图中为某个列启用新的更合适的名字

例:建立信息系学生的视图

create view IS_Student as 
select Sno,Sname,Sage from Student 
where Sdept='IS'
with check option;

在定义时只是将视图的定义存入数据字典中,并不执行select语句。在对视图进行查询时,才按视图的定义从基本表中将数据查出。

添加了with check option语句后,以后对该视图进行更新、修改和删除操作时,数据库管理系统会自动加上Sdept='IS'条件。

行列子集视图:一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码。

例:建立信息系选修了1号课程的学生的视图

create view IS_S1(Sno,Sname,Grade)
as
select Student.Sno,Sname,Grade
from Student,SC
where Sdept='IS' and Student.Sno=SC.Sno and SC.Cno='1';

带表达式的视图:视图中存在一些根据实际应用需要设置的虚拟属性列

例:建立一个反应学生出生年份的视图

create view BT_S(Sno,Sname,Sbirth) as
select Sno,Sname,2014-age from Student;

分组视图:视图中存在聚集函数和group by查询子句

例:将学生的学号及平均成绩定义成一个视图

create view S_G(Sno,Grade) as
select Sno,avg(Grade) from SC group by Sno;

2、删除视图

drop view 视图名(cascade;

使用级联子句cascade可以删除关联指定视图的所有视图。

3.7.2 查询视图

视图定义后,查询视图与查询基本表的方法类似。

视图消解:从数据字典中去除视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询,然后再执行修正后的语句。

例:在信息系的学生中查找年龄小于20岁的学生

select Sno,Sage from Student where Sdept='IS' and Sage<20;

目前大多数关系数据库对行列子集视图的查询都能进行正确转换。

select Sno,avg(Grade) from SC group by Sno having avg(Grade)>=90;

定义视图并查询视图与基于派生表的查询是有区别的,视图一旦定义,其定义将永久保存在数据字典中,之后所有的查询都可以引用该视图。而派生表只是在语句执行时临时定义,语句执行后该定义及被删除。

3.7.3 更新视图

由于视图是不实际存储的虚表,因此对视图的更新最终要转换成对基本表的更新。

视图的定义已经简化了基本表的某些属性,因此在从视图中插入数据,修改数据,删除数据所需要的SQL语句相对少一点。

例:将学生‘201215122’的姓名改为刘辰

update IS_Student set Sname='刘辰' where Sno='201215122';
/*转换后的更新语句*/
update Student set Sname='刘辰' where Sno='201215122' and Sdept='IS';

有些视图是不可以更新的,例如使用聚集函数计算某些属性产生的视图。

3.7.4 视图的作用

  • 简化用户的操作
  • 使用户能以多种角度看待同一个数据
  • 对重构数据库提供一定程度的逻辑独立性
  • 对机密数据提供安全保护
  • 更清晰的表达查询
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值