Проверка контрольных цифр ИНН в запросе

23.12.25

Разработка - Запросы

Делюсь реализацией проверки корректности ИНН, полностью реализованной на языке запросов 1С, без кода (почти). Работает в любой конфигурации, где есть справочник Контрагенты с реквизитами ИНН и Код (я же писал "почти").

Зачем я это сделал?

У меня в базе много контрагентов, и мне нужно было быстро понять, у кого ИНН на самом деле валиден. Не найдя готовых решений на чистом языке запросов, я собрал свой вариант и выкладываю его здесь.

Этот запрос может быть полезен:

  •     как готовое решение для аудита данных
  •     как наглядный пример продвинутого использования языка запросов (преобразование строки в число, получение остатка от деления)

Я постарался сделать текст максимально читаемым и понятным: использовал осмысленные имена временных таблиц, разнёс логику по шагам и вынес каждую цифру ИНН в отдельное поле, чтобы избавиться от изначального "спагетти".

В результате выполнения вы получите две временные таблицы:

  •     КонтрагентыСВалиднымИНН
  •     КонтрагентыСНевалиднымИНН

При желании запрос легко адаптировать под проверку одного ИНН (например, в обработке ввода).

Ниже под спойлером спрятан текст запроса, после которого идёт описание его работы.

 
ВЫБРАТЬ
	Контрагенты.Ссылка КАК Ссылка,
	Контрагенты.ИНН КАК ИНН,
	Контрагенты.Код КАК Код
ПОМЕСТИТЬ ИННСКорректнойДлиной
ИЗ
	Справочник.Контрагенты КАК Контрагенты
ГДЕ
	Контрагенты.ИНН <> ""
	И ДЛИНАСТРОКИ(Контрагенты.ИНН) = 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
;

////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ ИННСКорректнойДлиной

 

 

Как это работает? Пошагово

  1. ИННСКорректнойДлиной — отбираем контрагентов с ИНН длиной 10 или 12 символов (форматы юрлиц и ИП).

  2. Разряды — формируем таблицу степеней десятки (1, 10, 100, ..., 1011), чтобы позже умножать цифры на их вес.

  3. ИННЧислами — через ПОДСТРОКА сопоставляем каждый символ ИНН с цифрами из строки "0123456789", умножаем на соответствующий разряд и суммируем. Получаем числовое значение ИНН.

  4. Цифры — для удобства вычислений каждая цифра ИНН (от первой до последней) извлекается в отдельное поле (Цифра1, Цифра2, ...).

  5. КонтрольныеЦифры — по официальным формулам ФНС рассчитываются контрольные цифры:     

    • для 10-значного ИНН — одна

    • для 12-значного — две.

  6. КонтрагентыСВалиднымИНН — сравниваем вычисленные контрольные цифры с фактическими (последними цифрами ИНН).

  7. КонтрагентыСНевалиднымИНН — остаются те, кто не прошёл проверку.

Все промежуточные таблицы (Разряды, ИННЧислами, Цифры, КонтрольныеЦифры) уничтожаются по мере ненадобности.

Вступайте в нашу телеграмм-группу Инфостарт

язык запросов ИНН Контрольная сумма

См. также

SALE! %

Инструментарий разработчика Роли и права Запросы СКД Программист Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 15500 руб.

02.09.2020    236243    1287    419    

1102

Инструментарий разработчика Запросы Программист 1С:Предприятие 8 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    8220    110    zup_dev    22    

78

Инструментарий разработчика Запросы Программист 1С:Предприятие 8 1С:ERP Управление предприятием 2 Абонемент ($m)

В данной публикации рассказывается о решении, которое позволяет находить сразу все ошибки в тексте запроса за раз, а не только самую первую.

2 стартмани

05.03.2025    5331    19    XilDen    12    

29

Обновление 1С Запросы Программист 1С:Предприятие 8 1С:ERP Управление предприятием 2 Абонемент ($m)

Данный инструмент помогает анализировать доработанную конфигурацию после обновления на новый релиз и находить «битые» тексты запросов, в которых участвуют несуществующие в новом релизе метаданные.

3 стартмани

06.02.2025    4855    30    XilDen    26    

42

Запросы Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

В статье приведена удобная возможность отладки исполняемого запроса динамического списка.

03.12.2024    10761    artemusII    11    

27

Запросы Программист Бесплатно (free)

Увидел cheatsheet по SQL и захотелось нарисовать подобное, но про запросы.

18.10.2024    20215    sergey279    18    

73

Запросы Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    14953    XilDen    38    

110
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. chuevsf 84 23.12.25 18:24 Сейчас в теме
Проверял на 1С:ERP Управление предприятием 2 (2.5.25.77)

Это точно есть?
 Контрагенты.Код КАК Код
2. Неопределено 106 24.12.25 01:57 Сейчас в теме
(1)
Работает в любой конфигурации, где есть справочник Контрагенты с реквизитами ИНН и Код
Я вставил его как шутку, чтобы решение было не совсем без кода. Его можно убрать и это не повлияет на результат.
3. shard 289 24.12.25 02:36 Сейчас в теме
Оставлю это здесь - выдает таблицу не валидных ИНН. Работает чуть побыстрее. Про "Код" - в типовой УТ отсутствует.
ВЫБРАТЬ 0 КАК Цифра,"0" КАК Символ ПОМЕСТИТЬ ВТ_Соответствие
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	1,	"1"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	2,	"2"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	3,	"3"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	4,	"4"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	5,	"5"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	6,	"6"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	7,	"7"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	8,	"8"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ	9,	"9"
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	Контрагенты.Ссылка КАК КонтрагентСсылка,
	Контрагенты.ИНН КАК ИНН
ПОМЕСТИТЬ ВТ
ИЗ
	Справочник.Контрагенты КАК Контрагенты
ГДЕ
	Контрагенты.ИНН <> ""
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ВТ.КонтрагентСсылка КАК КонтрагентСсылка,
	ВТ.ИНН КАК ИНН,
	ВТ_11.Цифра ЕСТЬ NULL КАК ЭтоЮЛ,
	ВЫБОР
		КОГДА ВТ_11.Цифра ЕСТЬ NULL
			ТОГДА 2 * ВТ_1.Цифра + 4 * ВТ_2.Цифра + 10 * ВТ_3.Цифра + 3 * ВТ_4.Цифра + 5 * ВТ_5.Цифра + 9 * ВТ_6.Цифра + 4 * ВТ_7.Цифра + 6 * ВТ_8.Цифра + 8 * ВТ_9.Цифра
		ИНАЧЕ 7 * ВТ_1.Цифра + 2 * ВТ_2.Цифра + 4 * ВТ_3.Цифра + 10 * ВТ_4.Цифра + 3 * ВТ_5.Цифра + 5 * ВТ_6.Цифра + 9 * ВТ_7.Цифра + 4 * ВТ_8.Цифра + 6 * ВТ_9.Цифра + 8 * ВТ_10.Цифра
	КОНЕЦ КАК КонтрольнаяСумма1,
	ВЫБОР
		КОГДА ВТ_11.Цифра ЕСТЬ NULL
			ТОГДА 0
		ИНАЧЕ 3 * ВТ_1.Цифра + 7 * ВТ_2.Цифра + 2 * ВТ_3.Цифра + 4 * ВТ_4.Цифра + 10 * ВТ_5.Цифра + 3 * ВТ_6.Цифра + 5 * ВТ_7.Цифра + 9 * ВТ_8.Цифра + 4 * ВТ_9.Цифра + 6 * ВТ_10.Цифра + 8 * ВТ_11.Цифра
	КОНЕЦ КАК КонтрольнаяСумма2,
	ВЫБОР
		КОГДА ВТ_11.Цифра ЕСТЬ NULL
			ТОГДА ВТ_10.Цифра
		ИНАЧЕ ВТ_11.Цифра
	КОНЕЦ КАК КонтрольнаяЦифра1,
	ВЫБОР
		КОГДА ВТ_11.Цифра ЕСТЬ NULL
			ТОГДА ВТ_10.Цифра
		ИНАЧЕ ВТ_12.Цифра
	КОНЕЦ КАК КонтрольнаяЦифра2
ПОМЕСТИТЬ ВТ_КонтрольныеСуммы
ИЗ
	ВТ КАК ВТ
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_1  ПО (ВТ_1.Символ = ПОДСТРОКА(ВТ.ИНН, 1, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_2  ПО (ВТ_2.Символ = ПОДСТРОКА(ВТ.ИНН, 2, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_3  ПО (ВТ_3.Символ = ПОДСТРОКА(ВТ.ИНН, 3, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_4  ПО (ВТ_4.Символ = ПОДСТРОКА(ВТ.ИНН, 4, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_5  ПО (ВТ_5.Символ = ПОДСТРОКА(ВТ.ИНН, 5, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_6  ПО (ВТ_6.Символ = ПОДСТРОКА(ВТ.ИНН, 6, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_7  ПО (ВТ_7.Символ = ПОДСТРОКА(ВТ.ИНН, 7, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_8  ПО (ВТ_8.Символ = ПОДСТРОКА(ВТ.ИНН, 8, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_9  ПО (ВТ_9.Символ = ПОДСТРОКА(ВТ.ИНН, 9, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_10 ПО (ВТ_10.Символ = ПОДСТРОКА(ВТ.ИНН, 10, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_11 ПО (ВТ_11.Символ = ПОДСТРОКА(ВТ.ИНН, 11, 1))
		ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Соответствие КАК ВТ_12 ПО (ВТ_12.Символ = ПОДСТРОКА(ВТ.ИНН, 12, 1))
;

////////////////////////////////////////////////////////////­////////////////////
ВЫБРАТЬ
	ВТ_КонтрольныеСуммы.КонтрагентСсылка КАК КонтрагентСсылка,
	ВТ_КонтрольныеСуммы.ИНН КАК ИНН
ИЗ
	ВТ_КонтрольныеСуммы КАК ВТ_КонтрольныеСуммы
ГДЕ
	ЕСТЬNULL(ВЫБОР
				КОГДА ВТ_КонтрольныеСуммы.ЭтоЮЛ = ИСТИНА
					ТОГДА ВТ_КонтрольныеСуммы.КонтрольнаяСумма1 - ЦЕЛ(ВТ_КонтрольныеСуммы.КонтрольнаяСумма1 / 11) * 11 в (ВТ_КонтрольныеСуммы.КонтрольнаяЦифра1,10)
				ИНАЧЕ ВТ_КонтрольныеСуммы.КонтрольнаяСумма1 - ЦЕЛ(ВТ_КонтрольныеСуммы.КонтрольнаяСумма1 / 11) * 11 в (ВТ_КонтрольныеСуммы.КонтрольнаяЦифра1,10)
						И ВТ_КонтрольныеСуммы.КонтрольнаяСумма2 - ЦЕЛ(ВТ_КонтрольныеСуммы.КонтрольнаяСумма2 / 11) * 11 в (ВТ_КонтрольныеСуммы.КонтрольнаяЦифра2,10)
			КОНЕЦ, ЛОЖЬ) = ЛОЖЬ
Показать
bulpi; SerVer1C; solinik; Dach; Sashares; nagimo; Berckk; chuevsf; Неопределено; +9 Ответить
4. Неопределено 106 24.12.25 02:59 Сейчас в теме
(3) Я сделал эту публикацию ради этого комментария :D
solinik; shard; bossikd; ixijixi; +4 Ответить
20. RustIG 1934 25.12.25 09:23 Сейчас в теме
(3) Соответствие - Запросом? интересно.... неформатное программирование :)
Алфавит (рус, англ) также можно...
5. glek 119 24.12.25 10:48 Сейчас в теме
Запустил на ЕРП. Выдало ряд контрагентов с невалидными ИНН.
Например ИНН 0245009716 или 0207006626 невалидные. Хотя организации с таким ИНН существуют.
Чет не то с алгоритмом))))
solinik; Dach; +2 Ответить
6. SerVer1C 997 24.12.25 13:17 Сейчас в теме
(5) Может нули надо убрать спереди ?
12. Неопределено 106 25.12.25 02:01 Сейчас в теме
(5) Это из-за лидирующих нулей. Я не подумал, что они могут встречаться. Получается, из таблицы ИННЧислами необходимо убрать условие
ИМЕЮЩИЕ
	СУММА(А.Порядок * Б.Степень) / МИНИМУМ(А.Порядок) > 999999999

Исправил текст запроса.
9. bulpi 217 24.12.25 19:40 Сейчас в теме
Автор, у Вас на выражение
СУММА(А.Порядок * Б.Степень) / МИНИМУМ(А.Порядок) КАК ИННЧислом
наложено условие
ИМЕЮЩИЕ
СУММА(А.Порядок * Б.Степень) / МИНИМУМ(А.Порядок) > 999999999

А в следующем запросе рассматривается случай
ГДЕ
ИННЧислами.ИННЧислом <= 9999999999

Я глубоко не вникал, но первое впечатление - это условие никогда не будет выполнено, и часть запроса бесполезна.
11. Неопределено 106 25.12.25 01:54 Сейчас в теме
(9) Это объединение. В первом запросе мы получаем ИНН с 12ю цифрами, а во тором с 10ю и складываем их в одну таблицу.
27. bulpi 217 25.12.25 11:13 Сейчас в теме
(11) Условия А>В и А<=В не могут быть выполнены одновременно. Подумайте, а не отписывайтесь. Впрочем, как хотите.
35. Неопределено 106 26.12.25 07:34 Сейчас в теме
(27) Они не выполняются одновременно. Предположим, что в таблице ИННЧислами есть 2 записи, ИНН которых равны 1234567890 и 123456789012. ИНН 1234567890 попадёт в таблицу Цифры по условию <= 9999999999 и будет разбит на цифры 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, NULL, NULL. ИНН 123456789012 попадёт в таблицу Цифры по условию > 999999999 и будет разбит на цифры 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2.
36. bulpi 217 26.12.25 16:44 Сейчас в теме
(35) Теперь да, все корректно. Но только после того, как Вы убрали условие :
ИМЕЮЩИЕ
СУММА(А.Порядок * Б.Степень) / МИНИМУМ(А.Порядок) > 999999999

До этого часть запроса была нерабочей.
10. alex_sayan 68 24.12.25 20:33 Сейчас в теме
И зачем ЭТО делать запросом?
13. Неопределено 106 25.12.25 02:20 Сейчас в теме
(10) Чтобы не перебирать десятки тысяч контрагентов ¯\_(ツ)_/¯. Получил сразу всех точно валидных и прошёлся уже только по ним чтобы получить по ИНН информацию из налоговой.
16. alex_sayan 68 25.12.25 08:03 Сейчас в теме
(13)
Проблемые = Новый Массив;
Выборка = Справочники.Контрагенты.Выбрать();
Пока Выборка.Следующий() Цикл
     Если Не ВалидныйИНН(Выборка.ИНН) Тогда
          Проблемные.Добавить(Выборка.Ссылка);
     КонецЕсли;   
КонецЦикла;
Показать

Вот так не вариант?
17. Неопределено 106 25.12.25 08:28 Сейчас в теме
(16) Ну конечно нет: 2+ млн. элементов — это приключение уже не на 20 минут. По глупости я решил сделать замер производительности и за 5 минут в пустом цикле было обработано только 260 тысяч элементов. Если туда воткнуть ещё и проверку, будет совсем грустно.
21. RustIG 1934 25.12.25 09:30 Сейчас в теме
(17) Я всегда говорил и писал, что на все алгоритмы нужно накладывать Допущения, чтобы сузить круг обрабатываемой информации. В вашем случае Допущение следующее - можно не рассматривать контрагентов, по которым уже были сделки - УПД например...

Но в целом, понимаю, что есть редкие ситуации, когда УПД нет, а проверить нужно 2млн+ ИНН.

2млн+ запросом - это какая память на сервере должна быть? не у всех это решение взлетит....1с зависнет
запрос нужно резать на пакеты
25. Неопределено 106 25.12.25 10:14 Сейчас в теме
(21)
Прикрепленные файлы:
28. RustIG 1934 25.12.25 11:13 Сейчас в теме
(25) Установленная память = 98 Гб - на сервере клиента, на моем ноуте = 8 Гб...
Я предполагаю, что у вас масштабы Озон и ВБ
Сколько стоит память на 512 Гб ? скажите, пож-та, простым землянам
30. Неопределено 106 25.12.25 13:23 Сейчас в теме
(28)
Прикрепленные файлы:
34. alex_sayan 68 25.12.25 17:28 Сейчас в теме
(17) за полтора часа провернёт 2 млн, так это разовая задача. А переливать миллионы записей между временными таблицами тоже не бесплатно. А самое главное - запрос очень непонятен и его тяжело будет перерабатывать (например, при обнаружении ошибки)
14. dehro 12 25.12.25 07:38 Сейчас в теме
ГДЕ
	Контрагенты.ИНН <> ""
	И ДЛИНАСТРОКИ(Контрагенты.ИНН) = 12


Если длина строки не ноль, то она точно не пустая. Первое условие излишне.
15. Неопределено 106 25.12.25 07:55 Сейчас в теме
(14) В моём случае это не совсем так. ИНН — Строка(12) с постоянной длиной. Даже если это пустая строка, значение которой равно "", она всё равно попадёт в результат при условии ГДЕ ДЛИНАСТРОКИ(Контрагенты.ИНН) = 12. Лишними здесь получаются условия сравнения длины строки с числом. Но я предположил, что у кого-то длина строки может быть переменной, поэтому сделал такое условие для универсальности.
18. Неопределено 106 25.12.25 09:04 Сейчас в теме
(15)
Прикрепленные файлы:
22. RustIG 1934 25.12.25 09:35 Сейчас в теме
(18) здесь и помеченные на удаление попадут, родительские группы (с чатами :)) и с пустыми ИНН, сам алгоритм нужно оптимизировать... возможно не так грустно все получится.... но запросом интересна сама мысль....

здесь есть другая сторона медали - время разработки такого запроса - не 30 минут же вы его составили и отладили - за то же самое время простой алгоритм прошелся бы по 2млн+ выдал бы "базу" для исправлений

так что если у вас почасовка, то вы не будете заморачиваться над "гением" своей работы...

ПС. Хорошо, что у вас не "почасовка" :)
24. Неопределено 106 25.12.25 10:12 Сейчас в теме
(22) Я не измерял. Где-то за полдня сделал, отвлекаясь на него от основных задач. У меня этот цикл до сих пор выполняется. Почти 2 часа прошло, а он обработал только 880 тысяч элементов.
26. shard 289 25.12.25 10:36 Сейчас в теме
(24) а запросом за сколько обработалось? Любопытно еще в запросе деление на умножение заменить, оценить разницу
31. Неопределено 106 25.12.25 13:27 Сейчас в теме
(26) Прошло ровно 5 часов, отработало 1.7 млн. элементов. Запрос выполняется 3 секунды.
По поводу умножения даже не знаю, актуально ли это до сих пор. Могу протестировать переделанный запрос, но я столько времени переписывал его чтобы разбить на отдельные цифры и он был более понятным... Устал я его редактировать :D
Прикрепленные файлы:
29. RustIG 1934 25.12.25 11:21 Сейчас в теме
(24)
	
	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ
	|	Контрагенты.Ссылка,
	|	Контрагенты.ИНН
	|ИЗ
	|	Справочник.Контрагенты КАК Контрагенты
	|ГДЕ
	|	Контрагенты.ПометкаУдаления = ЛОЖЬ
	|	И Контрагенты.ЭтоГруппа = ЛОЖЬ
	|	И Контрагенты.ИНН <> """"";
	
	Результат = Запрос.Выполнить();
	Выборка = Результат.Выбрать();
	
	Пока Выборка.Следующий() Цикл   	
		//здесь проверяем ИНН
		ПроверитьИНН(Выборка.ИНН);		
	КонецЦикла;     
Показать


Список контрагентов для цикла надо готовить заранее - вот как здесь - у вас память позволяет вытащить такой список из базы в память. В очередной статье я писал , что обход справочника пообъектно применяется, когда памяти не хватает, чтобы вытащить весь список объектов через запрос, но это затратная операция.

В вашем случае, при наличии такой ОЗУ вы все равно начали использовать пообъектное чтение из базы... Ну никуда не годится. Поэтому негоже сравнивать ваш запрос и ваш обход цикла пообъектно.
Прикрепленные файлы:
32. Неопределено 106 25.12.25 13:29 Сейчас в теме
(29) Это я человеку из (16) пытаюсь объяснить зачем использовать запрос, а выборку он предложил в качестве альтернативы и я пытаюсь донести почему этот вариант не подходит. Просто как-то промазал с ответом, а когда заметил, отредактировать уже было нельзя.
33. RustIG 1934 25.12.25 13:56 Сейчас в теме
(32) мне тоже интересно, так что я вас понял, больше не отвлекаю :)
23. dehro 12 25.12.25 09:35 Сейчас в теме
(15) Да, странно как-то со строкой фиксированной длины.
Для отправки сообщения требуется регистрация/авторизация