Olá,
esta semana necessitei de criar um script para validação do NIF, número de identificação fiscal, mais conhecido por número de contribuinte.
O código foi implementado em numa linguagem diferente mas achei interessante recriar o mesmo em TSQL.
Explicações mais profundas sobre esta matéria podem consultar por ex. aqui:
https://pt.m.wikipedia.org/wiki/N%C3%BAmero_de_identifica%C3%A7%C3%A3o_fiscal
Vou apenas resumir o algoritmo a implementar:
O NIF é constituído por nove dígitos, sendo os oito primeiros sequenciais e o último um dígito de controlo. Adicionalmente, o primeiro dígito do NIF não pode ser zero nem quatro.
Para ser calculado o digito de controlo:
Multiplicar 1º digito por 9, o 2.º dígito por 8, o 3.º dígito por 7, o 4.º dígito por 6, o 5.º dígito por 5, o 6.º dígito por 4, o 7.º dígito por 3 e o 8.º dígito por 2.
Seguidamente somar os resultados.
Calcular o resto da divisão do número por 11: se o resto for 0 (zero) ou 1 (um) o dígito de controlo será 0 (zero); se for outro qualquer algarismo X o dígito de controlo será o resultado da subtracção 11 – X.
Por fim, basta ver a igualdade do dígito de controlo com o último dígito do NIF. No caso de ser igual o NIF está correcto; no caso de ser diferente o NIF não é válido.
O código TSQL foi colocado como uma função. Esta é chamada com um NIF e o retorno será o próprio NIF se estiver válido ou vazio caso não o seja.
Denominei a função como [dbo].[up_check_nif] e codifica-se da seguinte forma:
/*
Função valida NIF,
2021 JG
*/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
if OBJECT_ID('[dbo].[up_check_nif]') IS NOT NULL drop function dbo.up_check_nif
GO
CREATE function [dbo].up_check_nif (@nif_input varchar(9))
RETURNS varchar(9)
AS
BEGIN
declare @j int = 9
declare @i int = 1
declare @total int = 0
declare @digit_control int
declare @result varchar(9)
-- nif_pri_digito = '1,2,3,5,6,7,8,9'
IF LEN(@nif_input) = 9 AND @nif_input NOT LIKE '%[^0-9]%' AND LEFT(@nif_input,1) not in (0,4)
BEGIN
-- SUM( primeiros 8 digitos * [9,8,7,6,5,4,3,2])
WHILE @i < LEN(@nif_input)
BEGIN
SET @total = @total + SUBSTRING(@nif_input,@i,1) * @j
SET @j = @j-1
SET @i = @i+1
END
IF (@total % 11) = 0 OR (@total % 11) = 1
SET @digit_control = 0
ELSE
SET @digit_control = 11 - (@total % 11)
IF @digit_control = RIGHT(@nif_input,1)
SET @result = @nif_input /* nif válido */
ELSE
SET @result = '' /* nif inválido */
END
ELSE
SET @result = '' /* nif inválido */
RETURN @result
END
A função poderá ser chamada da seguinte forma:
select dbo.up_check_nif(‘123456789’) AS NIF_Validado
Espero que vos seja útil,
JG
Muito Bom !
Obrigado, Jorge, pela partilha, muito útil esta função.
Com base nesta função, alterei-a de modo a não usar loops e passar a usar sets.
Desta maneira o algoritmo fica mais rápido e, eventualmente mais importante, pode-se facilmente alterar o algoritmo para ser usado diretamente nos campos do SELECT ou na cláusula WHERE, nos casos em que não for permitido criar ou usar funções.
Obrigado!
Cumprimentos,
João Cristóvão
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
if OBJECT_ID(‘[dbo].[up_check_nif]’) IS NOT NULL drop function dbo.up_check_nif
GO
CREATE function [dbo].up_check_nif (@nif_input varchar(9))
RETURNS varchar(9)
AS
BEGIN
DECLARE @result varchar(9)
SELECT @result = CASE
WHEN len(@nif_input) 9 THEN ”
WHEN @nif_input LIKE ‘%[^0-9]%’ THEN ”
WHEN left(@nif_input, 1) IN (0,4) THEN ”
WHEN SUM(N) % 11 IN (0,1) THEN
CASE
WHEN right(@nif_input, 1) = ‘0’ THEN @nif_input
ELSE ”
END
ELSE
CASE
WHEN right(@nif_input, 1) = 11 – SUM(N) % 11 THEN @nif_input
ELSE ”
END
END
FROM (
VALUES
(9 * SUBSTRING(@nif_input, 1, 1))
,(8 * SUBSTRING(@nif_input, 2, 1))
,(7 * SUBSTRING(@nif_input, 3, 1))
,(6 * SUBSTRING(@nif_input, 4, 1))
,(5 * SUBSTRING(@nif_input, 5, 1))
,(4 * SUBSTRING(@nif_input, 6, 1))
,(3 * SUBSTRING(@nif_input, 7, 1))
,(2 * SUBSTRING(@nif_input, 8, 1))
) v(n)
RETURN @result
END