Зачем я это сделал?
У меня в базе много контрагентов, и мне нужно было быстро понять, у кого ИНН на самом деле валиден. Не найдя готовых решений на чистом языке запросов, я собрал свой вариант и выкладываю его здесь.
Этот запрос может быть полезен:
- как готовое решение для аудита данных
- как наглядный пример продвинутого использования языка запросов (преобразование строки в число, получение остатка от деления)
Я постарался сделать текст максимально читаемым и понятным: использовал осмысленные имена временных таблиц, разнёс логику по шагам и вынес каждую цифру ИНН в отдельное поле, чтобы избавиться от изначального "спагетти".
В результате выполнения вы получите две временные таблицы:
- КонтрагентыСВалиднымИНН
- КонтрагентыСНевалиднымИНН
При желании запрос легко адаптировать под проверку одного ИНН (например, в обработке ввода).
Ниже под спойлером спрятан текст запроса, после которого идёт описание его работы.
ВЫБРАТЬ
Контрагенты.Ссылка КАК Ссылка,
Контрагенты.ИНН КАК ИНН,
Контрагенты.Код КАК Код
ПОМЕСТИТЬ ИННСКорректнойДлиной
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.ИНН <> ""
И ДЛИНАСТРОКИ(Контрагенты.ИНН) = 10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Контрагенты.Ссылка,
Контрагенты.ИНН,
Контрагенты.Код
ИЗ
Справочник.Контрагенты КАК Контрагенты
ГДЕ
Контрагенты.ИНН <> ""
И ДЛИНАСТРОКИ(Контрагенты.ИНН) = 12
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
0 КАК Степень,
1 КАК Порядок
ПОМЕСТИТЬ Разряды
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
1,
10
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
2,
100
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
3,
1000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
4,
10000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
5,
100000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
6,
1000000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
7,
10000000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
8,
100000000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
9,
1000000000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
10,
10000000000
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
11,
100000000000
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИННСКорректнойДлиной.Ссылка КАК Ссылка,
ИННСКорректнойДлиной.ИНН КАК ИНН,
СУММА(А.Порядок * Б.Степень) / МИНИМУМ(А.Порядок) КАК ИННЧислом
ПОМЕСТИТЬ ИННЧислами
ИЗ
ИННСКорректнойДлиной КАК ИННСКорректнойДлиной,
Разряды КАК А,
Разряды КАК Б
ГДЕ
Б.Степень < 10
И ПОДСТРОКА(ИННСКорректнойДлиной.ИНН, 12 - А.Степень, 1) = ПОДСТРОКА("0123456789", Б.Степень + 1, 1)
СГРУППИРОВАТЬ ПО
ИННСКорректнойДлиной.Код,
ИННСКорректнойДлиной.Ссылка,
ИННСКорректнойДлиной.ИНН
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ Разряды
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИННЧислами.Ссылка КАК Ссылка,
ИННЧислами.ИНН КАК ИНН,
ИННЧислами.ИННЧислом КАК ИННЧислом,
ЦЕЛ(ИННЧислами.ИННЧислом / 100000000000) КАК Цифра1,
ЦЕЛ(ИННЧислами.ИННЧислом / 10000000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10000000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра2,
ЦЕЛ(ИННЧислами.ИННЧислом / 1000000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 1000000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра3,
ЦЕЛ(ИННЧислами.ИННЧислом / 100000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра4,
ЦЕЛ(ИННЧислами.ИННЧислом / 10000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра5,
ЦЕЛ(ИННЧислами.ИННЧислом / 1000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 1000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра6,
ЦЕЛ(ИННЧислами.ИННЧислом / 100000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра7,
ЦЕЛ(ИННЧислами.ИННЧислом / 10000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра8,
ЦЕЛ(ИННЧислами.ИННЧислом / 1000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 1000) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра9,
ЦЕЛ(ИННЧислами.ИННЧислом / 100) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра10,
ЦЕЛ(ИННЧислами.ИННЧислом / 10) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра11,
ЦЕЛ(ИННЧислами.ИННЧислом) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом) / 10 - 0.5 КАК ЧИСЛО(15, 0))) КАК Цифра12
ПОМЕСТИТЬ Цифры
ИЗ
ИННЧислами КАК ИННЧислами
ГДЕ
ИННЧислами.ИННЧислом > 9999999999
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
ИННЧислами.Ссылка,
ИННЧислами.ИНН,
ИННЧислами.ИННЧислом,
ЦЕЛ(ИННЧислами.ИННЧислом / 1000000000),
ЦЕЛ(ИННЧислами.ИННЧислом / 100000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 10000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 1000000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 1000000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 100000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 10000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 1000) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 1000) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 100) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 100) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом / 10) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом / 10) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
ЦЕЛ(ИННЧислами.ИННЧислом) - 10 * (ВЫРАЗИТЬ(ЦЕЛ(ИННЧислами.ИННЧислом) / 10 - 0.5 КАК ЧИСЛО(15, 0))),
NULL,
NULL
ИЗ
ИННЧислами КАК ИННЧислами
ГДЕ
ИННЧислами.ИННЧислом <= 9999999999
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ ИННЧислами
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Цифры.Ссылка КАК Ссылка,
Цифры.ИНН КАК ИНН,
Цифры.ИННЧислом КАК ИННЧислом,
ВЫБОР
КОГДА Цифры.ИННЧислом < 10000000000
ТОГДА ВЫБОР
КОГДА Цифры.Цифра1 * 2 + Цифры.Цифра2 * 4 + Цифры.Цифра3 * 10 + Цифры.Цифра4 * 3 + Цифры.Цифра5 * 5 + Цифры.Цифра6 * 9 + Цифры.Цифра7 * 4 + Цифры.Цифра8 * 6 + Цифры.Цифра9 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 2 + Цифры.Цифра2 * 4 + Цифры.Цифра3 * 10 + Цифры.Цифра4 * 3 + Цифры.Цифра5 * 5 + Цифры.Цифра6 * 9 + Цифры.Цифра7 * 4 + Цифры.Цифра8 * 6 + Цифры.Цифра9 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0))) = 10
ТОГДА 0
ИНАЧЕ Цифры.Цифра1 * 2 + Цифры.Цифра2 * 4 + Цифры.Цифра3 * 10 + Цифры.Цифра4 * 3 + Цифры.Цифра5 * 5 + Цифры.Цифра6 * 9 + Цифры.Цифра7 * 4 + Цифры.Цифра8 * 6 + Цифры.Цифра9 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 2 + Цифры.Цифра2 * 4 + Цифры.Цифра3 * 10 + Цифры.Цифра4 * 3 + Цифры.Цифра5 * 5 + Цифры.Цифра6 * 9 + Цифры.Цифра7 * 4 + Цифры.Цифра8 * 6 + Цифры.Цифра9 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0)))
КОНЕЦ
ИНАЧЕ ВЫБОР
КОГДА Цифры.Цифра1 * 7 + Цифры.Цифра2 * 2 + Цифры.Цифра3 * 4 + Цифры.Цифра4 * 10 + Цифры.Цифра5 * 3 + Цифры.Цифра6 * 5 + Цифры.Цифра7 * 9 + Цифры.Цифра8 * 4 + Цифры.Цифра9 * 6 + Цифры.Цифра10 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 7 + Цифры.Цифра2 * 2 + Цифры.Цифра3 * 4 + Цифры.Цифра4 * 10 + Цифры.Цифра5 * 3 + Цифры.Цифра6 * 5 + Цифры.Цифра7 * 9 + Цифры.Цифра8 * 4 + Цифры.Цифра9 * 6 + Цифры.Цифра10 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0))) = 10
ТОГДА 0
ИНАЧЕ Цифры.Цифра1 * 7 + Цифры.Цифра2 * 2 + Цифры.Цифра3 * 4 + Цифры.Цифра4 * 10 + Цифры.Цифра5 * 3 + Цифры.Цифра6 * 5 + Цифры.Цифра7 * 9 + Цифры.Цифра8 * 4 + Цифры.Цифра9 * 6 + Цифры.Цифра10 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 7 + Цифры.Цифра2 * 2 + Цифры.Цифра3 * 4 + Цифры.Цифра4 * 10 + Цифры.Цифра5 * 3 + Цифры.Цифра6 * 5 + Цифры.Цифра7 * 9 + Цифры.Цифра8 * 4 + Цифры.Цифра9 * 6 + Цифры.Цифра10 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0)))
КОНЕЦ
КОНЕЦ КАК КонтрольнаяЦифра1,
ВЫБОР
КОГДА Цифры.ИННЧислом < 10000000000
ТОГДА 0
ИНАЧЕ ВЫБОР
КОГДА Цифры.Цифра1 * 3 + Цифры.Цифра2 * 7 + Цифры.Цифра3 * 2 + Цифры.Цифра4 * 4 + Цифры.Цифра5 * 10 + Цифры.Цифра6 * 3 + Цифры.Цифра7 * 5 + Цифры.Цифра8 * 9 + Цифры.Цифра9 * 4 + Цифры.Цифра10 * 6 + Цифры.Цифра11 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 3 + Цифры.Цифра2 * 7 + Цифры.Цифра3 * 2 + Цифры.Цифра4 * 4 + Цифры.Цифра5 * 10 + Цифры.Цифра6 * 3 + Цифры.Цифра7 * 5 + Цифры.Цифра8 * 9 + Цифры.Цифра9 * 4 + Цифры.Цифра10 * 6 + Цифры.Цифра11 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0))) = 10
ТОГДА 0
ИНАЧЕ Цифры.Цифра1 * 3 + Цифры.Цифра2 * 7 + Цифры.Цифра3 * 2 + Цифры.Цифра4 * 4 + Цифры.Цифра5 * 10 + Цифры.Цифра6 * 3 + Цифры.Цифра7 * 5 + Цифры.Цифра8 * 9 + Цифры.Цифра9 * 4 + Цифры.Цифра10 * 6 + Цифры.Цифра11 * 8 - 11 * (ВЫРАЗИТЬ((Цифры.Цифра1 * 3 + Цифры.Цифра2 * 7 + Цифры.Цифра3 * 2 + Цифры.Цифра4 * 4 + Цифры.Цифра5 * 10 + Цифры.Цифра6 * 3 + Цифры.Цифра7 * 5 + Цифры.Цифра8 * 9 + Цифры.Цифра9 * 4 + Цифры.Цифра10 * 6 + Цифры.Цифра11 * 8) / 11 - 0.5 КАК ЧИСЛО(15, 0)))
КОНЕЦ
КОНЕЦ КАК КонтрольнаяЦифра2
ПОМЕСТИТЬ КонтрольныеЦифры
ИЗ
Цифры КАК Цифры
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ Цифры
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
КонтрольныеЦифры.Ссылка КАК Ссылка,
КонтрольныеЦифры.ИНН КАК ИНН
ПОМЕСТИТЬ КонтрагентыСВалиднымИНН
ИЗ
КонтрольныеЦифры КАК КонтрольныеЦифры
ГДЕ
ВЫБОР
КОГДА КонтрольныеЦифры.ИННЧислом < 10000000000
ТОГДА КонтрольныеЦифры.ИННЧислом - ЦЕЛ(КонтрольныеЦифры.ИННЧислом / 10) * 10 = КонтрольныеЦифры.КонтрольнаяЦифра1
ИНАЧЕ ЦЕЛ((КонтрольныеЦифры.ИННЧислом - ЦЕЛ(КонтрольныеЦифры.ИННЧислом / 100) * 100) / 10) = КонтрольныеЦифры.КонтрольнаяЦифра1
И КонтрольныеЦифры.ИННЧислом - ЦЕЛ(КонтрольныеЦифры.ИННЧислом / 10) * 10 = КонтрольныеЦифры.КонтрольнаяЦифра2
КОНЕЦ
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ КонтрольныеЦифры
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИННСКорректнойДлиной.Ссылка КАК Ссылка,
ИННСКорректнойДлиной.ИНН КАК ИНН
ПОМЕСТИТЬ КонтрагентыСНевалиднымИНН
ИЗ
ИННСКорректнойДлиной КАК ИННСКорректнойДлиной
ЛЕВОЕ СОЕДИНЕНИЕ КонтрагентыСВалиднымИНН КАК КонтрагентыСВалиднымИНН
ПО ИННСКорректнойДлиной.Ссылка = КонтрагентыСВалиднымИНН.Ссылка
ГДЕ
КонтрагентыСВалиднымИНН.Ссылка ЕСТЬ NULL
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ ИННСКорректнойДлиной
Как это работает? Пошагово
-
ИННСКорректнойДлиной — отбираем контрагентов с ИНН длиной 10 или 12 символов (форматы юрлиц и ИП).
-
Разряды — формируем таблицу степеней десятки (1, 10, 100, ..., 1011), чтобы позже умножать цифры на их вес.
-
ИННЧислами — через ПОДСТРОКА сопоставляем каждый символ ИНН с цифрами из строки "0123456789", умножаем на соответствующий разряд и суммируем. Получаем числовое значение ИНН.
-
Цифры — для удобства вычислений каждая цифра ИНН (от первой до последней) извлекается в отдельное поле (Цифра1, Цифра2, ...).
-
КонтрольныеЦифры — по официальным формулам ФНС рассчитываются контрольные цифры:
-
для 10-значного ИНН — одна
-
для 12-значного — две.
-
-
КонтрагентыСВалиднымИНН — сравниваем вычисленные контрольные цифры с фактическими (последними цифрами ИНН).
-
КонтрагентыСНевалиднымИНН — остаются те, кто не прошёл проверку.
Все промежуточные таблицы (Разряды, ИННЧислами, Цифры, КонтрольныеЦифры) уничтожаются по мере ненадобности.
Вступайте в нашу телеграмм-группу Инфостарт
