PostgreSQL SQL 语言:数据类型

本文档为PostgreSQL 9.6.0文档,本转载已得到原译者彭煜玮授权。

1. 数字类型

数字类型由2、4或8字节的整数以及4或8字节的浮点数和可选精度小数组成。Table 8-2列出了所有可用类型。

Table 8-2. 数字类型


image


下面的几节详细描述这些类型。

1.1. 整数类型

类型smallint、integer和bigint存储各种范围的全部是数字的数,也就是没有小数部分的数字。试图存储超出范围以外的值将导致一个错误。

常用的类型是integer,因为它提供了在范围、存储空间和性能之间的最佳平衡。一般只有在磁盘空间紧张的时候才使用 smallint类型。而只有在integer的范围不够的时候才使用bigint。

SQL只声明了整数类型integer(或int)、smallint和bigint。类型int2、int4和int8都是扩展,也在许多其它SQL数据库系统中使用。

1.2. 任意精度数字

类型numeric可以存储非常多位的数字。我们特别建议将它用于货币金额和其它要求计算准确的数量。numeric值的计算在可能的情况下会得到准确的结果,例如加法、减法、乘法。不过,numeric类型上的算术运算比整数类型或者下一节描述的浮点数类型要慢很多。

在随后的内容里,我们使用了下述术语:一个numeric的比例是到小数部分的位数,numeric的精度是整个数字里全部位的数目,也就是小数点两边的位数目。因此数字 23.5141 的精度为6而比例为4。你可以认为整数的比例为零。

numeric列的最大精度和最大比例都是可以配置的。要声明一个类型为numeric的列,你可以用下面的语法:


NUMERIC(precision, scale)

精度必须为正数,比例可以为零或者正数。另外:


NUMERIC(precision)

选择比例为 0 。如果使用

NUMERIC

创建一个列时不使用精度或比例,则该列可以存储任何精度和比例的数字值,并且值的范围最多可以到实现精度的上限。一个这种列将不会把输入值转化成任何特定的比例,而带有比例声明的numeric列将把输入值转化为该比例(SQL标准要求缺省的比例是 0,即转化成整数精度。我们觉得这样做有点没用。如果你关心移植性,那你最好总是显式声明精度和比例)。

Note:
显式指定类型精度时的最大允许精度为 1000,没有指定精度的NUMERIC受到Table 8-2中描述的限制所控制。

如果一个要存储的值的比例比列声明的比例高,那么系统将尝试圆整(四舍五入)该值到指定的分数位数。 然后,如果小数点左边的位数超过了声明的精度减去声明的比例,那么抛出一个错误。

数字值在物理上是以不带任何前导或者后缀零的形式存储。 因此,列上声明的精度和比例都是最大值,而不是固定分配的 (在这个方面,numeric类型更类似于varchar(n), 而不像char(n))。 实际存储要求是每四个十进制位组用两个字节, plus three to eight bytes overhead.

除了普通的数字值之外,numeric类型允许特殊值NaN, 表示"不是一个数字"。任何在 NaN上面的操作都生成另外一个NaN。 如果在 SQL 命令里把这些值当作一个常量写,你必须在其周围放上单引号,例如UPDATE table SET x = 'NaN'。在输入时,字串NaN被识别为大小写无关。

Note: 在"不是一个数字"概念的大部分实现中,NaN被认为不等于任何其他数字值(包括NaN)。为了允许numeric值可以被排序和使用基于树的索引,PostgreSQL把NaN值视为相等,并且比所有非NaN值都要大。

类型decimal和numeric是等效的。两种类型都是SQL标准的一部分。

在对值进行圆整时,numeric类型会圆到远离零的整数,而(在大部分机器上)real和double precision类型会圆到最近的偶数上。例如:


SELECT x,
  round(x::numeric) AS num_round,
  round(x::double precision) AS dbl_round
FROM generate_series(-3.5, 3.5, 1) as x;
  x   | num_round | dbl_round
------+-----------+-----------
 -3.5 |        -4 |        -4
 -2.5 |        -3 |        -2
 -1.5 |        -2 |        -2
 -0.5 |        -1 |        -0
  0.5 |         1 |         0
  1.5 |         2 |         2
  2.5 |         3 |         2
  3.5 |         4 |         4
(8 rows)

1.3. 浮点类型

数据类型real和double precision是不准确的、变精度的数字类型。实际上,这些类型是IEEE标准 754 二进制浮点算术(分别对应单精度和双精度)的一般实现, 一直到下层处理器、操作系统和编译器对它的支持。

不准确意味着一些值不能准确地转换成内部格式并且是以近似的形式存储的,因此存储和检索一个值可能出现一些缺失。 处理这些错误以及这些错误是如何在计算中传播的主题属于数学和计算机科学的一个完整的分支, 我们不会在这里进一步讨论它,这里的讨论仅限于如下几点:

如果你要求准确的存储和计算(例如计算货币金额),应使用numeric类型。

如果你想用这些类型做任何重要的复杂计算,尤其是那些你对范围情况(无穷、下溢)严重依赖的事情,那你应该仔细评诂你的实现。

用两个浮点数值进行等值比较不可能总是按照期望地进行。

在大部分平台上,real类型的范围是至少 -1E+37 到 +1E+37,精度至少是 6 位小数。double precision类型通常有 -1E+308 到 +1E+308 的范围,精度是至少 15 位数字。太大或者太小的值都会导致错误。 如果输入数字的精度太高,那么可能发生园整。太接近零的数字,如果无法与零值的表现形式相区分就会产生下溢错误。

Note:
extra_float_digits设置控制当一个浮点值被转换为文本输出时要包括的额外有效数字的数目。其默认值为0,在每一个PostgreSQL支持的平台上输出都相同。增加该设置将产生能更精确表示存储值的输出,但是可能无法移植。

除了普通的数字值之外,浮点类型还有几个特殊值:

  • Infinity
  • -Infinity
  • NaN

这些值分别表示 IEEE 754 特殊值"正无穷大"、"负无穷大"以及"不是一个数字"(在不遵循 IEEE 754 浮点算术的机器上,这些值的含义可能不是预期的)。如果在 SQL 命令里把这些数值当作常量写,你必须在它们周围放上单引号,例如UPDATE table SET x = 'Infinity'。 在输入时,这些串是以大小写无关的方式识别的。

Note:
IEEE754指定NaN不应该与任何其他浮点值(包括NaN)相等。为了允许浮点值被排序或者在基于树的索引中使用,PostgreSQL将NaN值视为相等,并且比所有非NaN值要更大。

PostgreSQL还支持 SQL 标准表示法float和float(p)用于声明非精确的数字类型。在这里,p指定以二进制位表示的最低可接受精度。 在选取real类型的时候,PostgreSQL接受float(1)到float(24),在选取double precision的时候,接受float(25)到float(53)。在允许范围之外的p值将导致一个错误。没有指定精度的float将被当作是double precision。

Note: 认为real和double precision分别有 24 和 53 个二进制位的假设对 IEEE 标准的浮点实现来说是正确的。在非 IEEE 平台上,这个数值可能略有偏差,但是为了简化,我们在所有平台上都用了同样的p值范围。

1.4. 序数类型

smallserial、serial和bigserial类型不是真正的类型,它们只是为了创建唯一标识符列而存在的方便符号(类似其它一些数据库中支持的AUTO_INCREMENT属性)。 在目前的实现中,下面一个语句:


CREATE TABLE tablename (
    colname SERIAL
);

等价于以下语句:


CREATE SEQUENCE tablename_colname_seq;
CREATE TABLE tablename (
    colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);

ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
因此,我们就创建了一个整数列并且把它的缺省值安排为从一个序列发生器取值。应用了一个NOT NULL约束以确保空值不会被插入(在大多数情况下你可能还希望附加一个UNIQUE或者PRIMARY KEY约束避免意外地插入重复的值,但这个不是自动发生的)。最后,该序列被标记为"属于"该列,这样当列或表被删除时该序列也会被删除。

Note: 因为smallserial、serial和bigserial是用序列实现的,所以即使没有删除过行,在出现在列中的序列值可能有“空洞”或者间隙。如果一个从序列中分配的值被用在一行中,即使该行最终没有被成功地插入到表中,该值也被“用掉”了。例如,当插入事务回滚时就会发生这种情况。更多信息参见Section 9.16中的nextval()。

要使用serial列插入序列的下一个数值到表中, 请指定serial列应该被赋予其缺省值。我们可以通过在INSERT语句中把该列排除在列列表之外来实现,也可以通过使用DEFAULT关键字来实现。

类型名serial和serial4是等效的: 两个都创建integer列。类型名bigserial和serial8也一样,只不过它们创建一个 bigint列。如果你预计在表的生存期中使用的标识符数目超过 231 个,那么你应该使用bigserial。类型名smallserial和serial2也以相同方式工作,只不过它们创建一个smallint列。

为一个serial列创建的序列在所属的列被删除的时候自动删除。你可以在不删除列的情况下删除序列,但是这会强制删除该列的默认值表达式。

2. 货币类型

money类型存储固定小数精度的货币数字,参阅Table 8-3。小数的精度由数据库的lc_monetary设置决定。表中展示的范围假设有两个小数位。可接受的输入格式很多,包括整数和浮点数文字,以及常用的货币格式,如'$1,000.00'。 输出通常是最后一种形式,但和区域相关。

Table 8-3. 货币类型

image

由于这种数据类型的输出是区域敏感的,因此将money数据装入到一个具有不同lc_monetary设置的数据库是不起作用的。为了避免这种问题,在恢复一个转储到一个新数据库中之前,应确保新数据库的lc_monetary设置和被转储数据库的相同或者具有等效值。

数据类型numeric、int和bigint的值可以被造型成money。从数据类型real和double precision的转换可以通过先造型成numeric来实现,例如:


SELECT '12.34'::float8::numeric::money;

但是,我们不推荐这样做。浮点数不应该被用来处理货币,因为浮点数可能会有圆整错误。

一个money值可以在不损失精度的情况下被造型成numeric。转换到其他类型可能会丢失精度,并且必须采用两个阶段完成:


SELECT '52093.89'::money::numeric::float8;

当一个money值被另一个money值除时,结果是double precision(即一个纯数字,而不是金额),在除法中货币单位被约掉了。

3. 字符类型

Table 8-4. 字符类型


image


Table 8-4显示了在PostgreSQL里可用的一般用途的字符类型。

SQL定义了两种基本的字符类型: character varying(n)和character(n), 其中n是一个正整数。两种类型都可以存储最多n个字符长的串。试图存储更长的串到这些类型的列里会产生一个错误, 除非超出长度的字符都是空白,这种情况下该串将被截断为最大长度(这个看上去有点怪异的例外是SQL标准要求的)。 如果要存储的串比声明的长度短,类型为character的值将会用空白填满;而类型为character varying的值将只是存储短些的串。

如果我们明确地把一个值造型成character varying(n)或者character(n), 那么超长的值将被截断成n个字符,而不会抛出错误(这也是SQL标准的要求)。

varchar(n)和char(n)的概念分别是character varying(n)和character(n)的别名。没有长度声明词的character等效于character(1)。如果不带长度说明词使用character varying,那么该类型接受任何长度的串。后者是一个PostgreSQL的扩展。

另外,PostgreSQL提供text类型,它可以存储任何长度的串。尽管类型text不是SQL标准,但是许多其它 SQL 数据库系统也有它。

类型character的值物理上都用空白填充到指定的长度n, 并且以这种方式存储和显示。不过,拖尾的空白被当作是没有意义的,并且在比较两个 character类型值时不会考虑它们。在空白有意义的排序规则中,这种行为可能会 产生意料之外的结果,例如SELECT 'a '::CHAR(2) collate "C" < E'an'::CHAR(2)会返回真(即便C区域会认为一个空格比新行更大)。当把一个character值转换成其他 字符串类型之一时,拖尾的空白会被移除。请注意,在character varying和text值里, 结尾的空白语意上是有含义的,并且在使用模式匹配(如LIKE和正则表达式)时也会被考虑。

这些类型的存储需求是 4 字节加上实际的字串,如果是 character 的话再加上填充的字节。长的字串将会自动被系统压缩, 因此在磁盘上的物理需求可能会更少些。长的数值也会存储在后台表里面,这样它们就不会干扰对短字段值的快速访问。 不管怎样,允许存储的最长字串大概是 1 GB。 (允许在数据类型声明中出现的的 n 的最大值比这还小。 修改这个行为没有甚么意义,因为在多字节编码下字符和字节的数目可能差别很大。 如果你想存储没有特定上限的长字串,那么使用 text 或者没有长度声明词的 character varying, 而不要选择一个任意长度限制。) 一个短串(最长126字节)的存储要求是1个字节外加实际的串,该串在character情况下包含填充的空白。长一些的串在前面需要4个字节而不是1个字节。长串会被系统自动压缩,这样在磁盘上的物理需求可能会更少。非常长的值也会被存储在背景表中,这样它们不会干扰对较短的列值的快速访问。在任何情况下,能被存储的最长的字符串是1GB(数据类型定义中n能允许的最大值比这个值要小。修改它没有用处,因为对于多字节字符编码来说,字符的数量和字节数可能完全不同。如果你想要存储没有指定上限的长串,使用text或没有长度声明的character varying,而不是给出一个任意长度限制)。

Tip: 这三种类型之间没有性能差别,只不过是在使用填充空白的类型的时候需要更多存储尺寸,以及在存储到一个有长度约束的列时需要少量额外CPU周期来检查长度。虽然在某些其它的数据库系统里,character(n)有一定的性能优势,但在PostgreSQL里没有。事实上,character(n)通常是这三种类型之中最慢的一个,因为它需要额外的存储开销。在大多数情况下,应该使用text或者character varying。

Example 8-1. 使用字符类型


CREATE TABLE test1 (a character(4));
INSERT INTO test1 VALUES ('ok');
SELECT a, char_length(a) FROM test1; -- (1)
  a   | char_length
------+-------------
 ok   |           2

CREATE TABLE test2 (b varchar(5));
INSERT INTO test2 VALUES ('ok');
INSERT INTO test2 VALUES ('good      ');
INSERT INTO test2 VALUES ('too long');
ERROR:  value too long for type character varying(5)
INSERT INTO test2 VALUES ('too long'::varchar(5)); -- explicit truncation
SELECT b, char_length(b) FROM test2;
   b   | char_length
-------+-------------
 ok    |           2
 good  |           5
 too l |           5
(1)

在PostgreSQL里另外还有两种定长字符类型,在Table 8-5里显示。 name类型只用于在内部系统目录中存储标识符并且不是给一般用户使用的。该类型长度当前定为 64 字节(63 可用字符加结束符)但在C源代码应该使用常量 NAMEDATALEN引用。这个长度是在编译的时候设置的(因而可以为特殊用途调整),缺省的最大长度在以后的版本可能会改变。类型"char"(注意引号)和 char(1)是不一样的,它只用了一个字节的存储空间。它在系统内部用于系统目录当做简化的枚举类型用。

Table 8-5. 特殊字符类型

image

4. 二进制数据类型

bytea数据类型允许存储二进制串,参见Table 8-6。

Table 8-6. 二进制数据类型

image


二进制串是一个八位位组(或字节)的序列。 二进制串和字符串的区别有两个: 首先,二进制串明确允许存储零值的字节以及其它"不可打印的"字节(通常是位于范围 32 到 126 之外的字节)。 字符串不允许零字节,并且也不允许那些对于数据库的选定字符集编码是非法的任何其它字节值或者字节值序列。 第二,对二进制串的操作会处理实际上的字节,而字符串的处理和取决于区域设置。 简单说,二进制字串适用于存储那些程序员认为是"裸字节"的数据,而字符串适合存储文本。

bytea类型支持两种用于输入和输出的外部格式:PostgreSQL的历史的"逃逸"格式和"十六进制"格式。在输入时这两种格式总是会被接受。输出格式则取决于配置参数bytea_output,其默认值为十六进制(注意十六进制格式是在PostgreSQL 9.0中被引入的,早期的版本和某些工具无法理解它)。

SQL标准定义了一种不同的二进制串类型, 叫做BLOB或者BINARY LARGE OBJECT。其输入格式和bytea不同,但是提供的函数和操作符大多一样。

8.4.1. bytea的十六进制格式

"十六进制"格式将二进制数据编码为每个字节2个十六进制位,最高有效位在前。整个串以序列x开头(用以和逃逸格式区分)。在某些情景中,开头的反斜线可能需要通过双写来逃逸,在相同的情况中逃逸格式必须要双写反斜线,下文描述了细节。十六进制位可以是大写也可以是小写,在位对之间可以有空白(但是在位对内部以及开头的x序列中不能有空白)。十六进制格式和很多外部应用及协议相兼容,并且其转换速度要比逃逸格式更快,因此人们更愿意用它。

例子:


SELECT E'\\xDEADBEEF';

8.4.2. bytea的逃逸格式

"逃逸"格式是bytea类型的传统PostgreSQL格式。它采用将二进制串表示成ASCII字符序列的方法,而将那些无法用ASCII字符表示的字节转换成特殊的逃逸语句。从应用的角度来看,如果将字节表示为字符有意义,那么这种表示将很方便。但是在实际中,这常常是令人困扰的,因为它使二进制串和字符串之间的区别变得模糊,并且这种特别的逃逸机制也有点难于处理。因此这种格式可能会在大部分新应用中避免使用。

在逃逸模式下输入bytea值时,某些值的字节必须被逃逸,而所有的字节值都可以被逃逸。通常,要逃逸一个字节,需要把它转换成与它的三位八进制值, 并且前导一个反斜线(或者两个反斜线,如果使用逃逸串语法将值写成一个字面含义)。反斜线本身(字节值92)也可以用双写的反斜线表示。Table 8-7显示了必须被逃逸的字符,并给出了可以使用的替代逃逸序列。

Table 8-7. bytea文字逃逸字节


image

逃逸"不可打印的"字节的要求取决于区域设置。在某些实例中,你可以不理睬它们,让它们保持未逃逸的状态。注意在Table 8-7的每一个例子中的结果的长度正好是一个字节,即使其输出表示有时超过一个字符。

如Table 8-7中所示,要求多个反斜线的原因是写成一个串文字的输入串在PostgreSQL服务器中必须经过两个分析阶段。每一对中的第一个反斜线被串文字分析器(假设使用了逃逸串语法)解释为一个逃逸字符并且因此被消耗,只留下该对中的第二个反斜线(美元符号包围的串可以被用于防止这一层的逃逸)。剩下的反斜线接着被bytea输入函数识别为开始一个三位八进制值或逃逸另一个反斜线。例如,一个传递给服务器的串文字是E'\001',它在通过逃逸串分析器后变成001。001接着被送给bytea输入函数,这里它被转换成一个十进制值为1的单字节。注意单引号字符串不会被bytea特殊对待,因此它遵循串文字的正常规则。

Bytea字节有时在输出时被逃逸。通常,每一个"不可打印的"字节会被转换成与之等效的三位八进制值并且前置一个反斜线。大部分"可打印的"字节被表示为它们在客户端字符集中的标准表示形式。十进制值为92(反斜线)的字节在输出时被双写。详情请见Table 8-8。

Table 8-8. bytea输出逃逸字节


image


根据你使用的PostgreSQL前端,你在逃逸和未逃逸bytea串方面可能需要做额外的工作。例如,如果你的接口自动翻译换行和回车,你可能也不得不逃逸它们。

5. 日期/时间类型

PostgreSQL支持SQL中所有的日期和时间类型,如Table 8-9所示。这些数据类型上可用的操作如Section 9.9所述。日期根据公历来计算,即使对于该历法被引入之前的年份也一样(见Section B.4)。

Table 8-9. 日期/时间类型

image


Note: SQL要求只写timestamp等效于timestamp without time zone,并且PostgreSQL鼓励这种行为。timestamptz被接受为timestamp with time zone的一种简写,这是一种PostgreSQL的扩展。

time、timestamp和interval接受一个可选的精度值 p,这个精度值声明在秒域中小数点之后保留的位数。缺省情况下,在精度上没有明确的边界,p允许的范围对timestamp和interval类型是从 0 到 6。

Note: 当timestamp值被存储为八字节整数(目前是默认情况)时,在整个值的范围上微秒精度是可用的。当timestamp值被存储为双精度浮点数(一个已被启用的编译时选项)时,那么精度的有效限制会小于 6。timestamp值是以 2000-01-01 午夜之前或之后以来的秒数存储的。当timestamp值被用浮点数实现时,在2000-01-01前后几年的日期可以达到微秒的精度,但是对于远一些的日子,精度会下降。注意使用浮点日期时间允许显示比上文所述更大范围的timestamp值:从 4713 BC 到 5874897 AD。

同一个编译时选项也决定了time和interval值被存储为浮点数或八字节整数。在浮点数的情况中,当间隔的尺寸增长时,大interval值在精度上会下降。

对于time类型,如果使用了八字节的整数存储,允许的p的范围是从 0 到 6,如果使用的是浮点数存储,那么这个范围是 0 到 10。

interval类型有一个附加选项,它可以通过写下面之一的短语来限制存储的fields的集合:


YEAR
MONTH
DAY
HOUR
MINUTE
SECOND
YEAR TO MONTH
DAY TO HOUR
DAY TO MINUTE
DAY TO SECOND
HOUR TO MINUTE
HOUR TO SECOND
MINUTE TO SECOND

注意如果fields和p被指定,fields必须包括SECOND,因为精度只应用于秒。

类型time with time zone是 SQL 标准定义的,但是该定义显示出了一些会影响可用性的性质。在大多数情况下, date、time、timestamp without time zone和timestamp with time zone的组合就应该能提供任何应用所需的全范围的日期/时间功能。

类型abstime和reltime是低精度类型,它们被用于系统内部。 我们不鼓励你在应用里面使用这些类型,这些内部类型可能会在未来的版本里消失。

5.1. 日期/时间输入

日期和时间的输入可以接受几乎任何合理的格式,包括 ISO 8601、SQL-兼容的、传统POSTGRES的和其他的形式。 对于一些格式,日期输入里的日、月和年的顺序会让人混淆, 并且支持指定所预期的这些域的顺序。把DateStyle参数设置为MDY,就是选择“月-日-年”的解释,设置为DMY就是 “日-月-年”,而YMD是 “年-月-日”。

PostgreSQL在处理日期/时间输入上比SQL标准要求的更灵活。

请记住任何日期或者时间的文字输入需要由单引号包围,就象一个文本字符串一样。SQL要求下面的语法


type [ (p) ] 'value'

其中p是一个可选的精度声明,它给出了在秒域中的小数位数目。精度可以被指定给time、timestamp和interval类型。这允许前文所述的值。如果在一个常数声明中没有指定任何精度,它将默认取文字值的精度。

5.1.1. 日期

Table 8-10显示了date类型可能的输入方式。

Table 8-10. 日期输入


image


5.1.2. 时间

当日时间类型是time [ (p) ] without time zone和time [ (p) ] with time zone。 只写time等效于time without time zone。

这些类型的有效输入由当日时间后面跟着可选的时区组成(参阅Table 8-11和Table 8-12)。 如果在time without time zone的输入中指定了时区,那么它会被无声地忽略。你也可以指定一个日期但是它会被忽略,除非你使用了一个涉及到夏令时规则的时区,例如America/New_York。在这种情况下,为了判断是应用了标准时间还是夏令时时间,要求指定该日期。适当的时区偏移被记录在time with time zone值中。

Table 8-11. 时间输入


image


Table 8-12. 时区输入


image

1.3. 时间戳

时间戳类型的有效输入由一个日期和时间的串接组成,后面跟着一个可选的时区,一个可选的AD或者BC(另外,AD/BC可以出现在时区前面,但这个顺序并非最佳)。 因此:


1999-01-08 04:05:06

和:


1999-01-08 04:05:06 -8:00

都是有效的值,它遵循ISO 8601 标准。另外,使用广泛的格式:


January 8 04:05:06 1999 PST

也被支持。

SQL标准通过"+"或者"-"符号的存在以及时间后面的时区偏移来区分timestamp without time zone和timestamp with time zone文字。因此,根据标准,


TIMESTAMP '2004-10-19 10:23:54'

是一个timestamp without time zone, 而


TIMESTAMP '2004-10-19 10:23:54+02'

是一个timestamp with time zone。PostgreSQL从来不会在确定文字串的类型之前检查其内容,因此会把上面两个都看做是 timestamp without time zone。因此要保证把上面的文字当作timestamp with time zone看待, 就要给它正确的显式类型:


TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'

如果一个文

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值