DECLARE @local_variable

本文介绍如何在SQL Server中使用DECLARE语句声明局部变量和游标变量,并提供了使用SET和SELECT语句为变量赋值的方法。此外,还详细说明了如何定义表数据类型,包括列定义、数据类型及约束。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DECLARE @local_variable 在批处理或过程的正文中用 DECLARE 语句声明变量,并用 SET 或 SELECT 语句给其指派值。游标变量可通过该语句声明,并且可用在其它与游标相关的语句中。所有变量在声明后均初始化为 NULL。 语法 DECLARE {{ @local_variable data_type } | { @cursor_variable_name CURSOR } | { table_type_definition } } [ ,...n] < table_type_definition > ::= TABLE ( { < column_definition > | < table_constraint > } [ ,...] ) < column_definition > ::= column_name scalar_data_type [ COLLATE collation_ name ] [ [ DEFAULT constant_expression ] | IDENTITY [ ( seed , increment ) ] ] [ ROWGUIDCOL ] [ < column_constraint > ] < column_constraint > ::= { [ NULL | NOT NULL ] | [ PRIMARY KEY | UNIQUE ] | CHECK ( logical_expression ) } < table_constraint > ::= { { PRIMARY KEY | UNIQUE } ( column_name [ ,...] ) | CHECK ( search_condition ) } 参数 是变量的名称。变量名必须以 at 符 (@) 开头。局部变量名必须符合标识符规则。有关更多信息,请参见使用标识符。 data_type 是任何由系统提供的或用户定义的数据类型。变量不能是 text、ntext 或 image 数据类型。有关系统数据类型的更多信息,请参见数据类型。有关用户定义数据类型的更多信息,请参见 。 是游标变量的名称。游标变量名必须以 at 符 (@) 开头并遵从标识符规则。 CURSOR 指定变量是局部游标变量。 table_type_definition 定义表数据类型。表声明包括列定义、名称、数据类型和约束。允许的约束类型只包括 PRIMARY KEY、UNIQUE KEY、NULL 和 CHECK。 table_type_definition 是在 CREATE TABLE 中用于定义表的信息子集。元素和基本定义都包含在该定义中;有关更多信息,请参见 。 n 是表示可以指定多个变量并对变量赋值的占位符。当声明表变量时,表变量必须是 DECLARE 语句中正在声明的唯一变量。 column_name 是表中的列名。 scalar_data_type 指定列是标量数据类型。 [COLLATE collation_name] 指定列的排序规则。collation_name 可以是 Windows 排序规则名称或 SQL 排序规则名称,且只适用于 char、varchar、text、nchar、nvarchar 和 ntext 数据类型的列。如果没有指定,则可给列指定用户定义数据类型的排序规则(如果列为用户定义数据类型)或数据库的默认排序规则。 有关 Windows 和 SQL 排序规则名称的更多信息,请参见 。 DEFAULT 如果在插入过程中未显式提供值,则指定为列提供的值。DEFAULT 定义可适用于除定义为 timestamp 或带 IDENTITY 属性的列以外的任何列。除去表时,将删除 DEFAULT 定义。只有常量值(如字符串)、系统函数(如 SYSTEM_USER())或 NULL 可用作默认参数。为保持与 SQL Server 早期版本的兼容,可以给 DEFAULT 指派约束名。 constant_expression 是用作列的默认值的常量、NULL 或系统函数。 IDENTITY 表示新列是标识列。在表中添加新行时,SQL Server 为列提供一个唯一的增量值。标识列通常与 PRIMARY KEY 约束一起用作表的唯一行标识符。可以将 IDENTITY 属性指派给 tinyint、smallint、int、decimal(p,0) 或 numeric(p,0) 列。对于每个表只能创建一个标识列。不能对标识列使用绑定默认值和 DEFAULT 约束。必须同时指定种子和增量,或者都不指定。如果二者都未指定,则取默认值 (1,1)。 seed 是装入表的第一行所使用的值。 increment 是添加到以前装载的列标识值的增量值。 ROWGUIDCOL 表示新列是行的全局唯一标识符列。对于每个表只能指派一个 uniqueidentifier 列作为 ROWGUIDCOL 列。ROWGUIDCOL 属性只能指派给 uniqueidentifier 列。 NULL | NOT NULL 是决定在列中是否允许空值的关键字。 PRIMARY KEY 是通过唯一索引对给定的一列或多列强制实体完整性的约束。对于每个表只能创建一个 PRIMARY KEY 约束。 UNIQUE 是通过唯一索引为给定的一列或多列提供实体完整性的约束。一个表可以有多个 UNIQUE 约束。 CHECK 是通过限制可输入到一列或多列中的可能值强制域完整性的约束。 logical_expression 是返回 TRUE 或 FALSE 的逻辑表达式。 注释 变量常用在批处理或过程中,作为 WHILE、LOOP 或 IF...ELSE 块的计数器。 变量只能用在表达式中,不能代替对象名或关键字。若要构造动态 SQL 语句,请使用 EXECUTE。 局部变量的作用域是在其中声明局部变量的批处理、存储过程或语句块。有关在语句块内使用局部变量的更多信息,请参见。 当前给其指派有游标的游标变量可在下列语句中作为源引用: 在所有这些语句中,如果引用的游标变量存在,但是不具有当前分配给它的游标,那么 Microsoft® SQL Server? 会产生错误。如果引用的游标变量不存在,SQL Server 将产生对另外一类未声明变量所产生的相同错误。 游标变量: 可以在 EXECUTE 语句中作为输出游标参数的目标引用(如果当前没有给游标变量指派游标)。 示例A. 使用 DECLARE 下例使用名为 @find 的局部变量检索所有姓以 Ring 开头的作者信息。 USE pubs DECLARE @find varchar(30) SET @find = 'Ring%' SELECT au_lname, au_fname, phone FROM authors WHERE au_lname LIKE @find 下面是结果集: au_lname au_fname phone -------------------------------------- -------------------- ------------ Ringer Anne 801 826-0752 Ringer Albert 801 826-0752 (2 row(s) affected) B. 在 DECLARE 中使用两个变量 下例从 Binnet & Hardley (pub_id = 0877) 的雇员中检索从 1993 年 1 月 1 日起所雇佣的雇员名称。 USE pubs SET NOCOUNT ON GO DECLARE @pub_id char(4), @hire_date datetime SET @pub_id = '0877' SET @hire_date = '1/01/93' -- Here is the SELECT statement syntax to assign values to two local -- variables. -- SELECT @pub_id = '0877', @hire_date = '1/01/93' SET NOCOUNT OFF SELECT fname, lname FROM employee WHERE pub_id = @pub_id and hire_date >= @hire_date 下面是结果集: fname lname -------------------- ------------------------------ Anabela Domingues Paul Henriot (2 row(s) affected
USE [DXQcontrol_VWAnhuiCP2PS01_Operational_W] GO /****** Object: StoredProcedure [dbo].[DS_SP_AlsAlarmsInsert] Script Date: 7/25/2025 9:45:04 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- 2005-08-22, SDR: Stores a new alarm in database -- 2006-02-28, JM: read the priority from the DS_AlsTags_TAB, if possible -- 2024-01-30, LZ: extend argument @arg_dynItemId from 11 to 17 digits -- internal component message number extend from 4 to 10 digits ALTER PROCEDURE [dbo].[DS_SP_AlsAlarmsInsert] @arg_utc_dts_new_on DATETIME, @arg_computer NVARCHAR(16), @arg_ionode NVARCHAR(32), @arg_ioitem NVARCHAR(64), @arg_text_id NVARCHAR(32), @arg_priority INT, @arg_localTimeDiff INT, -- offset in seconds from UTC to local time -- the following parameters are only valid for dynamic messages; -- for dynamic messages the meaning of "@arg_dynItemId" is the same -- like "@arg_ioitem" in case of static messages; -- all of these parameters are an empty string ('') for static messages @arg_dynItemId NVARCHAR(17), -- 17 character which includes: -- 1..4 : component -- 5..7 : device identifier -- 8..17 : internal component message number @arg_deviceId NVARCHAR(3), -- character 5..7 of @arg_dynItemId @arg_message NVARCHAR(128) AS BEGIN SET NOCOUNT ON; -- constants DECLARE @procName NVARCHAR(128) = OBJECT_SCHEMA_NAME(@@PROCID) + '.' + OBJECT_NAME(@@PROCID); DECLARE @lengthDynItemId TINYINT = 17; -- length of parameter @arg_dynItemId; use the variable instead of fix length inside the code -- variables DECLARE @iError INT; DECLARE @iRowCount INT; DECLARE @szErrType NVARCHAR(32); DECLARE @szErrMsg NVARCHAR(MAX); DECLARE @bDynAlarm TINYINT; DECLARE @bDynTagBreak TINYINT; DECLARE @szDynTextId NVARCHAR(32); DECLARE @szDynLamEnglish NVARCHAR(128); DECLARE @szDynToken NVARCHAR(128); DECLARE @bDynParamIndex TINYINT; DECLARE @sDynStartPos SMALLINT; DECLARE @sDynEndPos SMALLINT; DECLARE @ioitem NVARCHAR(64); DECLARE @cfg_inst_structure BIGINT; DECLARE @areakey NVARCHAR(96); DECLARE @plant_type CHAR(1); DECLARE @class CHAR(2); DECLARE @shiftnr TINYINT; DECLARE @wtmid INT; DECLARE @iAlsTagsPriority INT; DECLARE @local_dts_new_on DATETIME; DECLARE @tTypIdOfShift TINYINT; DECLARE @szSyncAlarms NVARCHAR(8); ------------------------------------------------------------------------------- -- Check the input parameters IF (@arg_utc_dts_new_on IS NULL OR @arg_computer IS NULL OR @arg_ionode IS NULL OR @arg_ioitem IS NULL OR @arg_priority IS NULL OR @arg_localTimeDiff IS NULL) BEGIN EXEC [dbo].[DS_SP_WriteToDSErrorLog] @procName, N'ERROR', N'Invalid parameters'; RETURN 0; END; IF (LEN(@arg_computer) = 0 OR LEN(@arg_ionode) = 0 OR LEN(@arg_ioitem) = 0) BEGIN EXEC [dbo].[DS_SP_WriteToDSErrorLog] @procName, N'ERROR', N'Invalid parameters'; RETURN 0; END; SET @szErrType = N'WARNING'; SET @szErrMsg = N''; SET @cfg_inst_structure = NULL; ------------------------------------------------------------------------------- -- check whether this is a dynamic alarm SET @bDynAlarm = 0; SET @ioitem = @arg_ioitem; IF (@arg_dynItemId IS NOT NULL AND @arg_deviceId IS NOT NULL) BEGIN IF (LEN(@arg_dynItemId) > 0 AND LEN(@arg_deviceId) > 0) BEGIN SET @bDynAlarm = 1; SET @ioitem = @arg_dynItemId; END; END; -- if (@arg_dynItemId is not null and @arg_deviceId is not null) IF (@bDynAlarm = 0) BEGIN SELECT TOP(1) @cfg_inst_structure = [cfg_inst_structure], @areakey = [areakey], @plant_type = [plant_type], @iAlsTagsPriority = [priority], @class = [class] FROM [dbo].[DS_AlsTags_TAB] WHERE ([ionode] = @arg_ionode AND [ioitem] = @ioitem) ORDER BY [id] DESC; SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; END; ELSE BEGIN BEGIN TRANSACTION; SET @iRowCount = 0; SELECT TOP(1) @cfg_inst_structure = ISNULL([DYN].[cfg_inst_structure], [DATT].[cfg_inst_structure]), @areakey = ISNULL([DYN].[areakey],[DATT].[areakey]), @plant_type = ISNULL([DYN].[plant_type],[DATT].[plant_type]), @iAlsTagsPriority = ISNULL([DYN].[priority],[DATT].[priority]), @class = ISNULL([DYN].[class],[DATT].[class]), @iRowCount = (CASE WHEN [DYN].[ionode] IS NULL THEN 0 ELSE 1 END) FROM [dbo].[DS_AlsTags_TAB] [DATT] WITH (ROWLOCK XLOCK) RIGHT JOIN [dbo].[DS_AlsDynTags_TAB] [DYN] WITH (ROWLOCK XLOCK) ON [DYN].[ionode] = [DATT].[ionode] AND [DYN].[ioitem] = [DATT].[ioitem] WHERE ([DYN].[ionode] = @arg_ionode AND [DYN].[ioitem] = @ioitem) ORDER BY [DYN].[id] DESC; IF @iRowCount = 0 BEGIN -- in case of dynamic tags the arg_priority is used INSERT INTO [dbo].[DS_AlsDynTags_TAB] ([ionode], [ioitem], [plant_id], [plant_type], [equipment_id], [devicename], [groupkey], [cfg_inst_structure], [text_id], [class], [location], [active], [priority], [log_enabled], [areakey]) SELECT @arg_ionode, @ioitem, [plant_id], [plant_type], [equipment_id], @arg_deviceId, [groupkey], [cfg_inst_structure], @arg_text_id, [class], [location], [active], @arg_priority, [log_enabled], [areakey] FROM [dbo].[DS_AlsTags_TAB] WHERE ([ionode] = @arg_ionode AND [ioitem] = @arg_ioitem); SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; SELECT TOP(1) @cfg_inst_structure = ISNULL([DYN].[cfg_inst_structure], [DATT].[cfg_inst_structure]), @areakey = ISNULL([DYN].[areakey],[DATT].[areakey]), @plant_type = ISNULL([DYN].[plant_type],[DATT].[plant_type]), @iAlsTagsPriority = ISNULL([DYN].[priority],[DATT].[priority]), @class = ISNULL([DYN].[class],[DATT].[class]), @iRowCount = (CASE WHEN [DYN].[ionode] IS NULL THEN 0 ELSE 1 END) FROM [dbo].[DS_AlsTags_TAB] [DATT] WITH (ROWLOCK XLOCK) RIGHT JOIN [dbo].[DS_AlsDynTags_TAB] [DYN] WITH (ROWLOCK XLOCK) ON [DYN].[ionode] = [DATT].[ionode] AND [DYN].[ioitem] = [DATT].[ioitem] WHERE ([DYN].[ionode] = @arg_ionode AND [DYN].[ioitem] = @ioitem) ORDER BY [DYN].[id] DESC; END; -- IF @iRowCount = 0 COMMIT TRANSACTION; END; -- else of 'if (@bDynAlarm = 0)' IF (@iError <> 0 OR @iRowCount <> 1) BEGIN SET @szErrMsg = N'AlarmTag does not exist for node '+ @arg_ionode + N' and item ' + @ioitem + N';error=' + CAST(@iError AS NVARCHAR(16)) + N';row count=' + CAST(@iRowCount AS NVARCHAR(16)); GOTO afterTransaction; END; ------------------------------------------------------------------------------- -- If this is a 'dynamic' or a 'dynamic direct' alarm then store -- the message text direct in the attribute 'message' of the new alarm -- Note: because of that direct storage only one language is supported -- in the attribute 'message' (the default language is 'en') SET @szDynLamEnglish = N''; IF (LEN(ISNULL(@arg_message,N'')) > 0) BEGIN IF (@bDynAlarm = 0 OR LEN(@arg_dynItemId) <> @lengthDynItemId) BEGIN -- this is a dynamic direct alarm, therefore we can -- take the native received message SET @szDynLamEnglish = @arg_message; END; ELSE BEGIN SET @szDynTextId = N'T02_' + SUBSTRING(@arg_dynItemId,1,4) + N'_' + SUBSTRING(@arg_dynItemId,8,10); IF LEN(@arg_text_id) >= 8 BEGIN -- check whether we the can use directly the text_id to search for the -- corresponding language format string -- we assume that the text_id is valid if the component (4 characters) -- and the text library number (4 characters) are included in the text_id IF (CHARINDEX(SUBSTRING(@arg_dynItemId,1,4), @arg_text_id, 1) > 0 AND CHARINDEX(SUBSTRING(@arg_dynItemId,8,10), @arg_text_id, 1) > 0) BEGIN SET @szDynTextId = @arg_text_id; END; END; SELECT TOP(1) @szDynLamEnglish = [en] FROM [dbo].[DS_LamTexts_TAB] WHERE ([text_id] = @szDynTextId AND [sub_id] = N'MESSAGE') ORDER BY [sub_id] ASC; SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; IF (@iError = 0 AND @iRowCount = 1 AND LEN(ISNULL(@szDynLamEnglish,N'')) > 0) BEGIN SET @bDynParamIndex = 0; SET @sDynStartPos = 1; SET @bDynTagBreak = 0; WHILE (@bDynTagBreak = 0) BEGIN SET @bDynParamIndex = @bDynParamIndex + 1; SET @sDynEndPos = CHARINDEX(N';', @arg_message, @sDynStartPos); IF (@sDynEndPos = 0 OR @sDynEndPos >= 128 OR @bDynParamIndex >= 9) BEGIN SET @sDynEndPos = LEN(@arg_message) + 1; SET @bDynTagBreak = 1; END; SET @szDynToken = N''; IF ((@sDynEndPos - @sDynStartPos) > 0) BEGIN SET @szDynToken = RTRIM(LTRIM(SUBSTRING(@arg_message, @sDynStartPos, @sDynEndPos - @sDynStartPos))); END; IF @bDynParamIndex = 1 BEGIN IF (LEN(@szDynToken) = 3) SET @szDynLamEnglish = REPLACE(@szDynLamEnglish, N'%id', @szDynToken); ELSE SET @szDynLamEnglish = REPLACE(@szDynLamEnglish, N'%id', @arg_deviceId); END; ELSE BEGIN SET @szDynLamEnglish = REPLACE(@szDynLamEnglish, N'%s' + CAST((@bDynParamIndex-1) AS NVARCHAR(16)), @szDynToken); END; SET @sDynStartPos = @sDynEndPos + 1; IF (@sDynStartPos > 128) BEGIN SET @bDynTagBreak = 1; END; END; -- WHILE (@bDynTagBreak = 0) END; --if (@iError = 0 and @iRowCount = 1 and len(isnull(@szDynLamEnglish,0)) > 0) ELSE BEGIN -- there exists no format string for this dynamic alarm -- therefore take the native received message SET @szDynLamEnglish = @arg_message; END; END; -- else of 'IF (@bDynAlarm = 0 OR LEN(@arg_dynItemId) <> 11)' END; --IF (LEN(ISNULL(@arg_message,N'')) > 0) ------------------------------------------------------------------------------- -- Insert a new dataset for the alarm if there is no open alarm registers for this tag -- If an alarm bit is operated by more than one AlarmServer then -- the following constallation can occure: -- AlarmServer 1 inserts a new alarm. This alarm went few seconds later. -- Now AlarmServer 2 process the same alarm and because of this the -- same alarm is stored duplicated in database. The probability of -- this occurance is higher for shorter alarm durations. -- -- Configuration to synchronize multiple AlarmServer with same alarm items -- * DS_GlobalParameter_TAB: set the value to "yes" for parameter -- "SynchronizeMultipleAlarmServer" and category "AlarmServer" -- List of programs which call the procedures DS_SP_AlsAlarmsInsert and DS_SP_AlsAlarmsUpdate -- * the AlarmServer -- - there exists max one AlarmServer per computer -- - there exist max two database connections per AlarmServer (primary and secondary database) -- (the primary and secondary database have to be different) -- - the alarms within the BUF files are processed in FIFO order by the C++ database DLL -- * the procedures DS_SP_PBS_AlarmHandling, DS_SP_WOPC_AlarmHandling -- SELECT TOP(1) @szSyncAlarms = [value] FROM [dbo].[DS_GlobalParameter_TAB] WITH (NOLOCK) WHERE [category] = N'AlarmServer' AND [parameter] = N'SynchronizeMultipleAlarmServer' AND [active] = 1 ORDER BY [id] DESC; IF @@ROWCOUNT = 0 SET @szSyncAlarms = N'no'; IF @szSyncAlarms = N'yes' BEGIN -- Enter critical section BEGIN TRANSACTION; IF EXISTS(SELECT 1 FROM [dbo].[DS_AlsAlarmsExclusiveLock_TAB] [DAAELT] WITH (ROWLOCK XLOCK HOLDLOCK) WHERE [DAAELT].[ionode] = @arg_ionode AND [DAAELT].[ioitem] = @ioitem) BEGIN UPDATE [dbo].[DS_AlsAlarmsExclusiveLock_TAB] WITH (ROWLOCK XLOCK HOLDLOCK) SET [maxDate] = @arg_utc_dts_new_on WHERE [ionode] = @arg_ionode AND [ioitem] = @ioitem AND [maxDate] < @arg_utc_dts_new_on; END; ELSE BEGIN INSERT INTO [dbo].[DS_AlsAlarmsExclusiveLock_TAB]([ionode],[ioitem],[maxDate]) VALUES (@arg_ionode,@ioitem,@arg_utc_dts_new_on); END; SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; COMMIT TRANSACTION; IF @iError <> 0 BEGIN SET @szErrType = N'ERROR'; SET @szErrMsg = N'Can not select from table DS_AlsAlarmsExclusiveLock_TAB for node '+ @arg_ionode + N' and item ' + @ioitem + N';error=' + CAST(@iError AS NVARCHAR(16)); END; IF @iRowCount = 0 BEGIN GOTO afterTransaction; END; END; -- if @szSyncAlarms = N'yes' ELSE BEGIN SELECT @iRowCount = 1, @iError = 0; END; -- write alarm logging IF @iRowCount = 1 AND @iError = 0 BEGIN SET @wtmid = -1; -- get the work time model ID for this alarm IF (@cfg_inst_structure IS NOT NULL) BEGIN SELECT TOP(1) @wtmid = [WTM_ID] FROM [dbo].[DS_CfgInstallationStructure_TAB] WHERE ([ID] = @cfg_inst_structure) ORDER BY [ID] DESC; SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; IF (@iError <> 0 OR @iRowCount <> 1) BEGIN SET @wtmid = -1; END; END; -- if (@cfg_inst_structure is not null) -- get the actual shift number SET @local_dts_new_on = DATEADD(ss,@arg_localTimeDiff,@arg_utc_dts_new_on); EXEC @shiftnr = [dbo].[DS_SP_GetShiftDetailsForDateEvt] @local_dts_new_on, @wtmid, @tTypIdOfShift OUTPUT, 1; -- 2022-10-20, debiezala -- use merge instead of insert to prevent double entries -- independant when how many AlarmServers are running MERGE INTO [dbo].[DS_AlsAlarms_TAB] AS [t] USING (VALUES (@arg_ionode, @ioitem) ) AS [s] ([ionode], [ioitem]) ON ([t].[ionode] = [s].[ionode] AND [t].[ioitem] = [s].[ioitem] AND [t].[utc_dts_gone_off] IS NULL) WHEN NOT MATCHED THEN INSERT ([utc_dts_new_on], [local_dts_new_on], [shift_nr], [computer], [text_id], [ionode], [ioitem], [message], [priority], [areakey], [plant_type], [class]) VALUES (@arg_utc_dts_new_on, @local_dts_new_on, @shiftnr, @arg_computer, @arg_text_id, @arg_ionode, @ioitem, @szDynLamEnglish, ISNULL(@iAlsTagsPriority, @arg_priority), @areakey, @plant_type, @class); SELECT @iError = @@ERROR, @iRowCount = @@ROWCOUNT; IF @iError <> 0 BEGIN SET @szErrType = N'ERROR'; SET @szErrMsg = N'Can not insert alarm message for node '+ @arg_ionode + N' and item ' + @ioitem + N';error=' + CAST(@iError AS NVARCHAR(16)) + N';row count=' + CAST(@iRowCount AS NVARCHAR(16)); GOTO afterTransaction; END; END; -- if @iRowCount = 0 and @iError = 0 afterTransaction: IF @szErrMsg <> N'' BEGIN EXEC [dbo].[DS_SP_WriteToDSErrorLog] @procName, @szErrType, @szErrMsg; END; RETURN 1; END; 分析以上存储过程
最新发布
07-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值