次の図は、GST識別番号の形式を示しています。
最初の2桁は、2011年インド国勢調査による一意の州コードを示します。たとえば、州コードニューデリーのは '07'で、カルナタカのそれは '29'です。
次の10文字は[〜#〜] pan [〜#〜](Permanent Account Number)納税者の。
13桁目は、登録番号(またはエンティティ番号)を示します同じ[〜#〜] pan [〜#〜]の納税者。
14桁目は、デフォルトではすべて「Z」です。現在、何も意図していません。
15桁目はチェックサムディジットです–数字またはアルファベット文字。
おそらく、PATINDEXまたはRegexを使用して検証を実行できますか?
これには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;
アーロンの完全に有効な回答を補足するために、あなたmightは、チェックディジットの正確さを検証することにより、GSTIN番号のより詳細な検証を行うことに決めました、番号の最後の桁として表示されます。
以下のコードは、新しい行を検証するためにCHECK CONSTRAINT
によって使用される多数の関数を作成し、GSTIN番号への変更を加えます。
最初の2つの関数は、GSTIN番号に含まれるASCII文字のbase-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');
最初の挿入は失敗します。 2番目と3番目の挿入は成功します。無効なGSTIN番号を挿入しようとすると、次のエラーが発生します。
メッセージ547、レベル16、状態0、行80
INSERTステートメントがCHECK制約「CK_t_valid_gstin」と競合しました。
データベース「tempdb」、テーブル「dbo.t」、列「i」で競合が発生しました。
制約の一部としてのスカラー関数の存在 並列処理を使用したクエリの防止 に注意してください。これは、システムに問題がある場合とない場合があります。並列処理が必要な場合は、テーブルでINSTEAD OF
トリガーを使用して、挿入または更新時に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');
このエラーが発生します:
メッセージ50000、レベル14、状態1、手順t_validate、行37 [バッチ開始行129]
無効なGSTIN番号を使用して挿入/更新しようとしました。
メッセージ3609、レベル16、状態1、行130
トランザクションはトリガーで終了しました。バッチは中止されました。
私は LUHNアルゴリズム を中心に実装を行いました。