以下图片描述了商品税标识号的格式:
也许我可以通过PATINDEX或Regex来执行验证?
发布于 2018-04-11 12:17:00
您不需要使用PATINDEX或RegEx。
CREATE TABLE #floob
(
GSTINColumn char(15),
CONSTRAINT CheckGSTINColumn CHECK
(
GSTINColumn LIKE '[0-9][0-9][0-9A-Z]'
+ '[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]'
+ '[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]'
+ '[0-9A-Z][0-9]Z[0-9A-Z]'
)
);
-- succeeds
INSERT #floob(GSTINColumn) VALUES('22AAAAA0000A1Z5');
GO
-- succeeds
INSERT #floob(GSTINColumn) VALUES('675T3E5600AZ7Z9');
GO
-- fails
INSERT #floob(GSTINColumn) VALUES('22AAAAA0000A1X5');
GO
DROP TABLE #floob;
发布于 2018-04-11 15:44:25
为了补充Aaron的完全有效的答案,您可能决定对GSTIN数字进行更深入的验证,方法是验证校验数字的正确性,这是数字中的最后一个数字。
下面的代码创建了许多函数,CHECK CONSTRAINT
将使用这些函数来验证新行,以及对GSTIN编号的任何修改。
前两个函数提供包含在GSTIN编号中的ASCII字符到基-36的任意映射;即0
映射到0
,9
映射到9
,A
映射到10
,Z
映射到35
:
IF OBJECT_ID(N'dbo.map_char', N'FN') IS NOT NULL
DROP FUNCTION dbo.map_char;
GO
CREATE FUNCTION dbo.map_char(@c char(1))
RETURNS int
AS
BEGIN
DECLARE @val int;
SET @c = UPPER(@c);
IF ASCII(@c) >= 48 AND ASCII(@c) <= 57
SET @val = ASCII(@c) - 48;
IF ASCII(@c) >= 65 AND ASCII(@c) <= 90
SET @val = (ASCII(@c) - 65) + 10;
RETURN @val;
END
GO
IF OBJECT_ID(N'dbo.unmap_char', N'FN') IS NOT NULL
DROP FUNCTION dbo.unmap_char;
GO
CREATE FUNCTION dbo.unmap_char(@v int)
RETURNS char(1)
AS
BEGIN
DECLARE @c char(1);
IF @v >= 0 AND @v <=9
SET @c = CHAR(@v + 48);
IF @v >= 10 AND @v <= 90
SET @c = CHAR((@v + 65) - 10);
RETURN @c;
END
GO
我一直无法确定印度政府是否使用同样的编码方式,但它似乎适用于所提供的价值观。
此代码使用上述dbo.map_char
函数验证给定GSTIN编号中的检查数字。
CREATE FUNCTION dbo.fn_validate_gstin
(
@inp char(15)
)
RETURNS tinyint
AS
BEGIN
DECLARE @return tinyint;
DECLARE @i int = LEN(@inp);
DECLARE @factor int = 1;
DECLARE @char char(1);
DECLARE @codepoint int;
DECLARE @addend int;
DECLARE @sum int = 0;
IF @i <> 15 /* GSTIN MUST be 15 characters to be valid */
BEGIN
SET @return = 0;
END
ELSE
BEGIN
WHILE @i > 0
BEGIN
SET @codepoint = dbo.map_char(SUBSTRING(@inp, @i, 1));
SET @addend = @factor * @codepoint;
SET @addend = (@addend / 36) + (@addend % 36);
SET @sum += @addend;
IF @factor = 2 SET @factor = 1 ELSE SET @factor = 2;
SET @i -= 1;
END
END
DECLARE @remainder int = @sum % 36;
IF @remainder = 0 SET @return = 1 ELSE SET @return = 0;
RETURN @return;
END
GO
注意,在这段代码中绝对没有错误检查;我把它作为一个练习留给读者。如果GSTIN包含一个有效的检查数字作为最后一个数字,则该函数返回1
。如果检查数字无效,则返回0。
在这里,我创建一个实现dbo.fn_validate_gstin
函数的表:
CREATE TABLE dbo.t
(
i char(15) NOT NULL
CONSTRAINT CK_t_valid_gstin
CHECK (dbo.fn_validate_gstin(i) = 1)
);
在这里我们插入了几个“测试”GSTIN号码:
INSERT INTO dbo.t (i) VALUES ('123456789012345');
INSERT INTO dbo.t (i) VALUES ('27AAFFM5744C1ZE');
INSERT INTO dbo.t (i) VALUES ('27AAACE7932L1ZC');
第一个插入失败。第二和第三插入成功。试图插入无效的GSTIN编号会导致以下错误:
Msg 547,级别16,状态0,第80行 INSERT语句与CHECK约束"CK_t_valid_gstin".冲突在数据库“.”、表"dbo.t“、列'i‘中发生冲突。
注意,标量函数作为约束防止使用并行性进行查询的一部分存在。这对您的系统可能有问题,也可能没有问题。如果需要并行性,可以考虑使用表上的INSTEAD OF
触发器在insert或update时检查GSTIN号。例如:
IF OBJECT_ID(N'dbo.t_with_trigger', N'U') IS NOT NULL
DROP TABLE dbo.t_with_trigger;
GO
CREATE TABLE dbo.t_with_trigger
(
i char(15) NOT NULL
);
GO
CREATE TRIGGER t_validate
ON dbo.t_with_trigger
INSTEAD OF INSERT, UPDATE
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE @bOk bit = 1;
IF EXISTS (
SELECT TOP(1) 1
FROM inserted i
WHERE dbo.fn_validate_gstin(i.i) = 0
UNION ALL
SELECT TOP(1) 1
FROM deleted d
WHERE dbo.fn_validate_gstin(d.i) = 0
)
BEGIN
SET @bOk = 0;
END
IF @bOk = 1
BEGIN
DELETE
FROM dbo.t_with_trigger
FROM dbo.t_with_trigger t
INNER JOIN deleted d ON t.i = d.i;
INSERT INTO dbo.t_with_trigger(i)
SELECT i.i
FROM inserted i;
COMMIT TRANSACTION;
END
ELSE
BEGIN
ROLLBACK TRANSACTION;
DECLARE @msg varchar(1000);
SET @msg = 'Attempted to insert/update using an invalid GSTIN number.';
RAISERROR (@msg, 14, 1);
END
END
GO
插入无效的GSTIN号码:
INSERT INTO dbo.t_with_trigger (i)
VALUES ('123456789012345')
, ('27AAFFM5744C1ZE')
, ('27AAACE7932L1ZC');
导致此错误:
Msg 50000、级别14、状态1、过程t_validate、第37行批处理起始线129 试图使用无效的GSTIN number. Msg 3609、级别16、状态1、130 插入/更新事务,事务在触发器中结束。批处理已被中止。
我的实现基于卢恩算法。
发布于 2022-04-15 07:32:45
为了检查GST号,您需要让它们保存DB。一旦在DB中可用,您就可以使用下面的代码在gst中通过select语句来设置pan、gst和pan。请记住,pan_in_gst是gst的子字符串,即SUBSTRING(table.field_name(gst),3,10)。
DECLARE @pan VARCHAR(10)
DECLARE @gst VARCHAR(15)
DECLARE @pan_in_gst VARCHAR(10)
DECLARE @v VARCHAR(5)
SET @pan = 'CABPG8363J'
SET @gst = '22CABPG8363J1Z1'
SET @pan_in_gst = 'CABPG8363A'
SET @v = CASE WHEN @pan = @pan_in_gst
THEN 'Yes'
ELSE 'No'
END
SELECT @pan AS 'Pan' , @gst AS 'GST', @pan_in_gst AS 'Pan IN GST', @v AS 'validation'
https://dba.stackexchange.com/questions/203612
复制相似问题