精通SQL技术:从基础到高级应用

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:SQL是一种广泛使用的结构化查询语言,用于管理和操作关系数据库。本课程将引导学生掌握SQL的核心操作,包括数据查询、数据库设计、性能优化以及复杂数据分析。深入学习涉及数据类型、数据库对象、JOIN操作、聚合函数、子查询、事务处理等关键知识点,旨在培养学生成为SQL技术的专家。 精通SQL技术精通SQL技术

1. SQL语言基础与数据库操作

数据库是信息管理的基础,而SQL(Structured Query Language)语言则是与数据库交互的基石。在这一章中,我们将从最基础的概念讲起,逐步深入到数据库的操作实践中。

SQL语言基础

SQL是一种专门用于存储、检索和操作关系数据库的国际标准语言。它包括数据查询(SELECT)、数据操纵(INSERT、UPDATE、DELETE)、数据定义(CREATE、ALTER、DROP)和数据控制(GRANT、REVOKE)等语句。

数据库操作

数据库操作包括对数据库中的数据进行增删改查等基本操作。其中,CRUD(创建Create、读取Read、更新***e、删除Delete)是数据库管理中最常见的操作。

例如,向数据库中插入一条记录的SQL语句可能如下所示:

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

阅读本章,将助你掌握SQL语言的基本结构,为进一步深入数据库管理和数据处理打下坚实基础。接下来的章节将逐步展开对数据类型、数据库对象、JOIN操作等更高级主题的探讨。

2. 数据类型与数据库对象

2.1 SQL中的数据类型

2.1.1 常见的数据类型及其应用场景

在数据库系统中,数据类型是定义表中列可以包含何种数据的属性。选择合适的数据类型对于优化数据库性能至关重要。以下是一些在SQL中常见的数据类型及其典型应用场景:

  • 整数类型 :如 INT SMALLINT ,通常用于存储整数值,例如人员编号、产品的库存数量等。
  • 字符类型 :如 CHAR VARCHAR ,用于存储字符串数据,如姓名、地址和文本信息。
  • 浮点数类型 :如 FLOAT REAL DOUBLE PRECISION ,用于存储数值数据,但包含小数部分,适合财务和科学计算。
  • 日期和时间类型 :如 DATE TIME DATETIME ,用于存储日期和时间信息,可以方便地进行日期时间相关的查询和计算。
  • 二进制数据类型 :如 BLOB BINARY ,用于存储二进制数据,比如图片、音频和视频文件等。
2.1.2 数据类型的转换与兼容性

在SQL中,数据类型之间的转换非常重要,尤其是涉及到不同数据类型间的计算和比较操作时。一些数据类型的转换是自动的,称为隐式转换,而有些则需要显式的转换。

  • 隐式转换 :通常发生在比较操作中,如一个整数和一个字符串进行比较时,数据库会将字符串隐式转换为整数。
  • 显式转换 :需要使用函数进行转换,例如 CAST CONVERT 函数,可以将数据从一种类型转换为另一种类型。

举个例子:

SELECT CAST('123' AS INT); -- 将字符串转换为整数

在实际应用中,需要谨慎处理数据类型转换,因为不恰当的转换可能导致数据损失或者转换错误。

2.2 数据库对象的创建与管理

2.2.1 表的创建与修改

在数据库中,表是最基本的对象之一,用于存储结构化的数据。创建表时,指定表名和一系列列及其对应的数据类型。这里是一个简单的创建表的例子:

CREATE TABLE employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    hire_date DATE,
    salary DECIMAL(10,2)
);

表创建后,可能需要添加或修改列来适应新的需求:

ALTER TABLE employees
ADD COLUMN middle_name VARCHAR(50),
MODIFY salary DECIMAL(12,2);
2.2.2 索引的使用与优化

索引是数据库中用于加快数据检索速度的一种数据结构。合理地使用索引能够显著提升查询性能,但同时也会增加写入操作的成本。创建索引的一般语法如下:

CREATE INDEX idx_employee_last_name ON employees(last_name);

索引的使用需要根据数据的查询模式进行优化。通常,应为频繁查询的列创建索引,尤其是 WHERE 子句中使用的列。但是需要注意的是,创建过多的索引会降低数据库的写入性能。

2.2.3 存储过程和触发器的编写与调试

存储过程是SQL语句和可选控制流语句的预编译集合,存储在数据库中。它们可以接受参数、返回结果集、执行复杂的业务逻辑。以下是创建存储过程的示例:

DELIMITER //
CREATE PROCEDURE GetEmployeeDetails(IN emp_id INT)
BEGIN
    SELECT * FROM employees WHERE id = emp_id;
END //
DELIMITER ;

触发器是一种特殊类型的存储过程,当数据库中发生特定事件时自动执行,例如在数据插入、更新或删除前后。编写和调试触发器需要对数据库的事务和事件有深刻的理解。

在实际数据库管理中,维护存储过程和触发器的代码质量和性能是保证数据库系统稳定性的重要环节。通过对数据库对象的创建与管理进行优化,可以极大地提升数据操作的效率和可靠性。

3. JOIN操作详解

3.1 内连接(INNER JOIN)的使用

3.1.1 基本语法和实例

内连接(INNER JOIN)是最常见的一种JOIN类型,用于将两个或多个表中的列进行匹配。只有当两个表中的列满足连接条件时,数据才会被返回。内连接的基本语法如下:

SELECT columns
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;

这里, INNER JOIN 表示只有当 table1.column_name table2.column_name 相等时,才返回这两个表的匹配行。 ON 子句用于指定连接条件。

实例分析:

假设我们有两个表,一个是 employees ,包含员工信息;另一个是 departments ,包含部门信息。我们要查询每个员工的姓名和他们所在的部门名称,SQL查询如下:

SELECT employees.name, departments.name AS department_name
FROM employees
INNER JOIN departments
ON employees.department_id = departments.id;

在这个例子中,通过 employees.department_id departments.id 的匹配来连接这两个表。返回的结果包含了匹配的员工姓名和部门名称。

3.1.2 高级连接场景

内连接的高级用法包括多表连接和连接条件的组合使用。例如,当我们需要从三个表中获取数据时,可以使用两次内连接:

SELECT orders.order_id, customers.name AS customer_name, employees.name AS employee_name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.id
INNER JOIN employees ON orders.employee_id = employees.id;

在这个查询中,我们从 orders 表出发,通过内连接分别连接 customers employees 表。这样可以获取每个订单对应的客户姓名和负责员工的姓名。

此外,内连接也可以与 WHERE 子句结合使用,通过添加额外的条件来进一步过滤数据:

SELECT products.name, categories.name AS category_name
FROM products
INNER JOIN categories ON products.category_id = categories.id
WHERE products.price > 50;

在这个查询中,我们不仅通过内连接从 products categories 表中获取数据,还通过 WHERE 子句添加了一个条件来过滤价格大于50元的产品。

3.2 外连接的多种用法

外连接扩展了内连接的概念,允许从一个表中返回所有行,即使没有找到匹配的行。根据返回行的来源不同,外连接可分为左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)。

3.2.1 左外连接(LEFT OUTER JOIN)

左外连接返回左表的所有行,即使右表中没有匹配的行也会返回左表的行。如果没有匹配的行,则相关联的列会是NULL。

SELECT customers.name, orders.order_id
FROM customers
LEFT OUTER JOIN orders ON customers.id = orders.customer_id;

在这个查询中,所有客户的姓名和他们的订单ID会被返回。如果某个客户没有订单( orders 表中没有匹配的行),那么订单ID将会是NULL。

3.2.2 右外连接(RIGHT OUTER JOIN)

右外连接与左外连接相对,它返回右表的所有行,即使左表中没有匹配的行也会返回右表的行。

SELECT products.name, categories.name AS category_name
FROM products
RIGHT OUTER JOIN categories ON products.category_id = categories.id;

这里我们试图获取所有产品的名称以及它们所属的分类名称。如果存在没有对应产品的分类,那么产品的名称将会是NULL。

3.2.3 全外连接(FULL OUTER JOIN)

全外连接返回左右两个表中的所有行。当没有匹配行时,相关联的列会是NULL。

SELECT products.name, categories.name AS category_name
FROM products
FULL OUTER JOIN categories ON products.category_id = categories.id;

这个查询中,所有产品和它们所属的分类都会被返回。对于没有分类的产品和没有产品的分类,相应的字段将会显示为NULL。

3.3 外连接在实际应用中的注意事项

在使用外连接时,需要注意以下几点:

  • 外连接要求使用 OUTER 关键字来指定,比如 LEFT OUTER JOIN
  • 使用外连接时,通常会结合 COALESCE() ISNULL() 函数来处理NULL值,以提高查询结果的可读性。
  • 在进行多表连接查询时,应该仔细考虑连接条件,避免因连接条件错误导致数据返回不符合预期。
  • 在某些数据库系统(如MySQL早期版本)中,可能需要使用特定的语法来实现全外连接,因为标准SQL的全外连接语法在这些系统中可能不可用。

外连接是处理数据库中不完整数据的重要工具。无论是数据缺失还是数据映射的需要,正确使用外连接可以有效解决许多复杂的数据查询和展示问题。在下一节中,我们将探讨如何在实际的业务场景中应用这些连接类型。

4. 分组与聚合函数的应用

4.1 分组查询(GROUP BY)的技巧

4.1.1 基本分组与聚合操作

分组查询是SQL中处理聚合数据的强大工具,它允许我们将数据集划分为更小的组,并对这些组应用聚合函数来计算统计数据。GROUP BY 子句在SELECT语句中使用,能够将数据行按指定的列进行分组。每个分组的聚合函数作用于该组内的所有记录,返回单个统计结果。

举个简单的例子,假设我们有一个销售订单表 orders ,想要统计每个销售人员的订单总额,我们可以使用如下查询:

SELECT salesman_id, SUM(amount) AS total_sales
FROM orders
GROUP BY salesman_id;

这里, GROUP BY salesman_id 表示结果集将根据销售人员的ID进行分组。 SUM(amount) AS total_sales 是一个聚合函数,它将为每个分组计算订单金额的总和。

4.1.2 分组过滤(HAVING子句)

在使用GROUP BY子句时,我们常常需要对分组后的结果进行过滤。这时候,就需要用到HAVING子句。HAVING子句允许我们对聚合后的结果集进行条件过滤,只有满足HAVING子句条件的分组才会被包含在最终结果中。

例如,如果我们想要找出订单总额超过10000的销售人员,可以使用以下查询:

SELECT salesman_id, SUM(amount) AS total_sales
FROM orders
GROUP BY salesman_id
HAVING SUM(amount) > 10000;

在这个查询中, HAVING SUM(amount) > 10000 将确保只有那些订单总额超过10000的销售人员才会显示在结果集里。

4.2 常用聚合函数的深入探讨

4.2.1 COUNT、SUM、AVG等函数的使用

聚合函数是SQL中对一组值执行计算并返回单个值的函数。常用的聚合函数包括:

  • COUNT() : 计算非NULL值的数量。
  • SUM() : 计算列的总和。
  • AVG() : 计算列的平均值。
  • MAX() : 返回列中的最大值。
  • MIN() : 返回列中的最小值。

每个聚合函数都可以在 SELECT 子句中独立使用,也可以与其他函数组合使用。例如,我们可以使用以下查询来找出订单表中最大和最小的订单金额:

SELECT MAX(amount) AS highest_order, MIN(amount) AS lowest_order
FROM orders;

4.2.2 聚合函数与分组组合使用的高级用法

聚合函数经常与GROUP BY子句一起使用,以提供对数据的更深入分析。例如,如果我们想要为每个销售人员计算平均订单金额,我们可以使用如下查询:

SELECT salesman_id, AVG(amount) AS avg_order_amount
FROM orders
GROUP BY salesman_id;

在这个例子中, AVG(amount) 计算了每个销售人员订单金额的平均值。若要限制查询结果只显示平均金额超过5000的销售人员,我们可以在HAVING子句中添加相应的条件:

SELECT salesman_id, AVG(amount) AS avg_order_amount
FROM orders
GROUP BY salesman_id
HAVING AVG(amount) > 5000;

表格:常用SQL聚合函数对比

| 函数名称 | 作用 | 示例用法 | |----------|------|----------| | COUNT() | 计数非NULL值的数量 | SELECT COUNT(column_name) FROM table_name; | | SUM() | 计算列的总和 | SELECT SUM(column_name) FROM table_name; | | AVG() | 计算列的平均值 | SELECT AVG(column_name) FROM table_name; | | MAX() | 返回列中的最大值 | SELECT MAX(column_name) FROM table_name; | | MIN() | 返回列中的最小值 | SELECT MIN(column_name) FROM table_name; |

聚合函数使得数据分析更加灵活,可以针对不同场景对数据进行汇总和分析。通过适当使用这些函数,我们可以快速获得有意义的业务洞察。

5. 子查询的嵌套使用

5.1 子查询基础

5.1.1 子查询的概念与分类

子查询是嵌套在另一个SQL查询语句中的查询。在理解子查询之前,我们需要清楚它的基本概念。子查询也可以理解为嵌套查询,它们可以被包含在 SELECT INSERT UPDATE DELETE 语句中。子查询返回的数据通常被用作父查询的条件。

子查询的分类可以基于它们在主查询中的位置进行区分,大致分为以下几类: - 标量子查询(返回单一值的子查询) - 列子查询(返回单列数据的子查询) - 行子查询(返回单行数据的子查询) - 表子查询(返回多行、多列数据的子查询)

理解这些分类对于编写有效且高效的SQL查询至关重要。

5.1.2 子查询的执行过程

子查询在执行时,首先处理内部查询,然后是外部查询。内部查询的结果通常作为外部查询的参数或条件使用。在逻辑上,子查询与嵌套的if-else条件逻辑相似,只不过是以查询的形式表现。

子查询执行过程中,数据库管理系统(DBMS)将首先解析内层查询,执行它,并将结果传递给外层查询。然后外层查询使用这些结果来执行它的逻辑。这种过程反复进行,直至整个查询执行完毕。

理解子查询的执行过程对于编写能够精确控制数据流向和逻辑结构的复杂查询至关重要。

5.2 子查询在不同场景的应用

5.2.1 WHERE子句中的子查询

WHERE 子句中使用子查询是常见的场景之一。这种子查询通常返回一个值,或值的列表,该值用于限定外部查询返回的结果集。

举一个简单的例子,假设我们需要查询员工表(employees)中部门号与特定部门号相同的员工。这种情况下,我们可以在 WHERE 子句中使用子查询来完成:

SELECT *
FROM employees
WHERE department_id = (
    SELECT department_id
    FROM departments
    WHERE department_name = 'Sales'
);

这段代码中,内部查询首先找出名称为"Sales"的部门的部门号,然后外部查询根据这个部门号筛选出相应的员工记录。

5.2.2 FROM子句中的子查询

FROM 子句中的子查询也被称为派生表或内联视图,其结果集可以被当作一个临时表来使用。这种用法在处理复杂的数据聚合时非常有用。

以下是一个示例,使用 FROM 子句中的子查询对数据进行分组:

SELECT region, AVG(salary)
FROM (
    SELECT region, salary
    FROM employees
) AS temp
GROUP BY region;

这里, SELECT region, salary 作为一个子查询,创建了一个临时表 temp 。外部查询随后根据 region 字段对 temp 表进行聚合计算。

5.2.3 SELECT子句中的子查询

SELECT 子句也可以包含子查询,通常是为了返回聚合数据或者动态的列值。一个简单的例子是,在一个查询中显示员工的名字和他/她的经理的名字:

SELECT 
    employees.name,
    (
        SELECT name
        FROM employees
        WHERE id = employees.manager_id
    ) AS manager_name
FROM employees;

在这个查询中,每个员工的名字与其经理的名字一同被检索出来,内部查询根据员工的 manager_id 检索出对应的经理名字。

子查询为数据库操作提供了极高的灵活性和强大的数据查询能力,掌握子查询的使用是任何想要精通SQL的专业人员必须掌握的技能之一。

6. 视图的创建与应用

6.1 视图的概念与创建

视图(View)是虚拟表,其内容由查询定义。视图包含一系列带有名称的列和行数据,其数据实际上来自定义视图的SQL语句所引用的表,这些表称为基表。视图提供了一种便捷的方式来封装复杂的SQL查询,同时提供数据的安全性和隔离性。在SQL中,视图可以看作是存储在数据库中的查询。

6.1.1 视图的作用与优势

视图可以简化复杂的SQL操作,因为可以通过创建视图来存储这些复杂的SQL,然后通过简单的查询视图来获取结果。对于数据库开发者来说,视图有以下优势:

  • 安全性 :使用视图可以隐藏表的特定部分,只向用户显示所需的数据,从而保护敏感数据。
  • 简化复杂查询 :视图可以作为复杂的多表JOIN操作的一个简单界面,使用者无需理解复杂的SQL语句。
  • 逻辑数据独立性 :如果底层表结构发生改变,视图可以维持一致的查询界面。
  • 数据独立性 :视图能够隔离应用程序和底层数据的变更,从而提高数据处理的安全性和灵活性。

6.1.2 创建视图的基本语法

创建视图的SQL语法相对简单,基本语法如下:

CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

其中, view_name 是你希望创建的视图名称, column1 , column2 等是视图中将要展示的列名, table_name 是视图所依赖的表名, condition 是筛选条件。

下面是一个创建视图的例子:

CREATE VIEW SalesSummary AS
SELECT 
    customer_name, 
    order_date, 
    SUM(amount) AS total_sales
FROM 
    customers, 
    orders
WHERE 
    customers.customer_id = orders.customer_id
GROUP BY 
    customer_name, 
    order_date;

这个视图 SalesSummary 将显示每个客户的名称、订单日期和总销售额。要查询这个视图,只需要执行 SELECT * FROM SalesSummary;

6.2 视图的管理和优化

在数据库中,视图同样需要进行管理和优化来保持性能和资源的高效利用。视图不是数据的实际存储点,它们存储的是SQL查询语句。这意味着每次访问视图时,数据库系统都会执行视图的SQL语句来获得数据。

6.2.1 视图的更新与删除

视图是可更新的(updatable),这意味着你可以通过视图来更新基表中的数据,条件是满足某些限制。以下是一些更新视图的规则:

  • 视图必须引用的是一个表,而不是另一个视图。
  • 视图定义中不能包含GROUP BY子句、DISTINCT关键字以及聚合函数。
  • 不能在视图上执行ORDER BY子句,除非同时使用了LIMIT子句。
  • 视图中不能包含子查询,除非子查询是单值的。

删除视图的语法如下:

DROP VIEW view_name;

6.2.2 视图的性能考量与优化方法

视图是数据库中一个非常有用的特性,但同样需要考虑性能。使用视图时应注意以下几点:

  • 视图的开销 :每次查询视图时,都需要重新执行视图定义中的SQL查询,这可能会带来额外的开销。
  • 索引的使用 :如果视图中涉及的字段被索引了,那么查询视图的速度会得到显著提升。
  • 材料化视图 :某些数据库系统(如Oracle)提供了材料化视图(Materialized View),它会存储查询结果,类似于一个快照,可以提升读取性能。

以下是一些优化视图性能的方法:

  • 创建必要的索引 :确保视图所依赖的表上有适当的索引,尤其是WHERE子句和JOIN操作中涉及的列。
  • 考虑使用存储过程 :在某些情况下,如果视图逻辑非常复杂,使用存储过程可能会有更好的性能。
  • 避免在视图上执行计算密集型操作 :尽量在视图中存储基础数据,将复杂计算放到应用层处理。

视图是一种强大的数据库特性,它们使得数据库的设计更加灵活,数据访问更加简洁。创建和使用视图时,务必要综合考虑性能和功能的平衡。

7. 事务处理的管理

7.1 事务的基本概念

7.1.1 事务的ACID属性

在关系型数据库中,事务是一组操作的集合,它们要么全部完成,要么全部不完成。这保证了数据的一致性和可靠性。事务具有以下四个基本属性,统称为ACID属性:

  • 原子性(Atomicity) :事务中的所有操作要么全部执行成功,要么全部不执行。如果事务中的任何一部分操作失败,那么整个事务都将回滚到操作执行前的状态。
  • 一致性(Consistency) :事务必须使数据库从一个一致性状态转换到另一个一致性状态。这意味着事务开始之前和结束之后,数据库的完整性约束没有被破坏。
  • 隔离性(Isolation) :隔离性是指一个事务的执行不应该被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(Durability) :事务处理结束后,对数据的修改是永久性的,即便系统故障也不会丢失。

7.1.2 事务的控制语句

在SQL中,可以使用以下控制语句来管理事务:

  • BEGIN TRANSACTION START TRANSACTION :开始一个新的事务。
  • COMMIT :提交当前事务,所有在该事务中进行的更改会永久保存到数据库中。
  • ROLLBACK :回滚当前事务,撤销所有在该事务中进行的更改。
  • SAVEPOINT :设置一个保存点,该点之后的事务可以被回滚而不影响前面的操作。
  • RELEASE SAVEPOINT :删除一个保存点。
  • SET TRANSACTION :设置事务的特性,如隔离级别等。

7.2 锁机制与并发控制

7.2.1 锁的类型和作用

数据库中的锁机制是用于控制多个事务同时对同一数据对象进行操作时,保证数据的一致性和完整性。锁的类型通常包括:

  • 共享锁(Shared Locks) :允许多个事务读取同一个资源,但不允许其他事务更新或删除该资源。
  • 排他锁(Exclusive Locks) :确保只有持有锁的事务可以读取或写入资源,其他任何事务都不能访问被锁定的资源。

此外,还有许多其他的锁类型,如意向锁、更新锁、范围锁等,它们用来解决更复杂的问题,如死锁预防和减少资源锁定时间。

7.2.2 死锁的预防与解决

死锁是指两个或多个事务在执行过程中,因争夺资源而造成的一种僵局。为避免死锁,可以采取以下预防措施:

  • 一次加锁法 :事务在开始时一次性申请所有需要的资源,避免中途加锁导致死锁。
  • 顺序加锁法 :事务按照一定的顺序申请资源,以避免循环等待的产生。
  • 资源排序法 :为资源编号,事务只能按照编号的顺序请求资源。
  • 超时法 :为事务设置一个等待时间,超时后事务自动回滚。

解决死锁通常需要数据库管理系统具备死锁检测机制,当检测到死锁后,系统会自动选择牺牲一个或多个事务来解决死锁,释放其持有的锁,让其他事务得以继续执行。

-- 示例:在事务中使用锁机制
BEGIN TRANSACTION;

-- 假设我们锁定表中的某些行,以进行更新操作
SELECT * FROM orders WHERE customer_id = 'C123' FOR UPDATE;

-- 更新操作
UPDATE orders SET status = 'Delivered' WHERE customer_id = 'C123';

-- 检查事务的更新
***T * FROM orders WHERE customer_id = 'C123';

COMMIT; -- 提交事务

在上述SQL代码中,我们使用了 FOR UPDATE 来对 orders 表中符合特定条件的行加排他锁,这意味着在当前事务未提交前,其他事务将无法更新这些行。这演示了在事务中使用锁来保证数据一致性的基本方法。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:SQL是一种广泛使用的结构化查询语言,用于管理和操作关系数据库。本课程将引导学生掌握SQL的核心操作,包括数据查询、数据库设计、性能优化以及复杂数据分析。深入学习涉及数据类型、数据库对象、JOIN操作、聚合函数、子查询、事务处理等关键知识点,旨在培养学生成为SQL技术的专家。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值