К статье
Практический материал

Разработка и Конфигурация · 11 мин

1С: как узнать, есть ли колонка в таблице значений

Как в 1С узнать, есть ли колонка в таблице значений: метод Найти() коллекции Колонки, проверка по имени и индексу, типичные ошибки и готовые примеры кода.

Таблица значений — один из самых используемых объектов встроенного языка 1С. Данные из запросов, файлов, внешних обработок и форм часто попадают именно в таблицу значений, и перед обращением к колонке важно убедиться, что она существует. Иначе код упадёт с ошибкой «Колонка не найдена» или «Поле объекта не обнаружено» при попытке прочитать Строка.НесуществующаяКолонка.

Проверка наличия колонки выполняется через коллекцию Колонки таблицы значений. Основной способ — метод Найти(ИмяКолонки), который возвращает объект колонки или Неопределено, если колонки с таким именем нет. Дополнительно можно перебрать коллекцию, проверить индекс или использовать структуру для отбора.

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

Основной способ: метод Найти() коллекции Колонки

У каждой таблицы значений есть свойство Колонки — коллекция объектов КолонкаТаблицыЗначений. У коллекции есть метод Найти(), который принимает имя колонки строкой и возвращает либо найденную колонку, либо Неопределено.

Если ТЗ.Колонки.Найти("Сумма") <> Неопределено Тогда

Сообщить("Колонка Сумма существует");

Иначе

Сообщить("Колонки Сумма нет");

КонецЕсли;

Найденную колонку удобно не только проверить, но и сразу использовать — например, получить её тип или индекс:

Колонка = ТЗ.Колонки.Найти("Сумма");

Если Колонка <> Неопределено Тогда

ТипКолонки = Колонка.ТипЗначения;

ИндексКолонки = ТЗ.Колонки.Индекс(Колонка);

КонецЕсли;

Поиск по имени нечувствителен к регистру: Найти("СУММА") и Найти("сумма") найдут колонку «Сумма». Это отличает имя колонки от имени переменной во встроенном языке в целом, но полагаться на это в динамическом коде всё равно стоит аккуратно — лучше передавать имя в том регистре, в котором колонка создана.

Как оформить проверку в универсальную функцию

В прикладном коде проверка наличия колонки нужна регулярно, поэтому её удобно вынести в общую функцию. Это снимает дублирование и делает вызов читаемым:

Функция ЕстьКолонка(ТаблицаЗначений, ИмяКолонки) Экспорт

Если ТаблицаЗначений = Неопределено Тогда

Возврат Ложь;

КонецЕсли;

Возврат ТаблицаЗначений.Колонки.Найти(ИмяКолонки) <> Неопределено;

КонецФункции

Обратите внимание на защиту от Неопределено: если таблица создаётся динамически (например, результат разбора файла может не сформироваться), обращение к Колонки у Неопределено вызовет исключение. Проверка входного параметра делает функцию безопасной для любых сценариев.

Часто требуется не просто узнать, есть ли колонка, а гарантировать её наличие: если нет — добавить. Для этого используется связка с методом Добавить():

Если ТЗ.Колонки.Найти("Комментарий") = Неопределено Тогда

ТЗ.Колонки.Добавить("Комментарий", Новый ОписаниеТипов("Строка"));

КонецЕсли;

Порядок действий
  1. 1
    Получите таблицу значений и убедитесь, что она не равна Неопределено
  2. 2
    Вызовите ТЗ.Колонки.Найти("ИмяКолонки") с нужным именем
  3. 3
    Сравните результат с Неопределено: не равно — колонка есть
  4. 4
    При необходимости добавьте колонку через Колонки.Добавить()
  5. 5
    Проверьте обращение к колонке в строке таблицы на тестовых данных

Проверка перебором и другие варианты

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

Перебор коллекции колонок

Перебор полезен, если критерий сложнее точного совпадения имени — например, поиск по подстроке или по типу значения колонки:

Найдена = Ложь;

Для Каждого Колонка Из ТЗ.Колонки Цикл

Если СтрНайти(ВРег(Колонка.Имя), "СУММА") > 0 Тогда

Найдена = Истина;

Прервать;

КонецЕсли;

КонецЦикла;

Проверка списка обязательных колонок

Когда обработка требует определённую структуру таблицы (например, при загрузке из Excel), удобно проверить все обязательные колонки одним циклом и собрать список недостающих:

Обязательные = СтрРазделить("Номенклатура,Количество,Цена", ",");

Для Каждого Имя Из Обязательные Цикл

Если ТЗ.Колонки.Найти(Имя) = Неопределено Тогда

Сообщить("Отсутствует колонка: " + Имя);

КонецЕсли;

КонецЦикла;

Обращение по индексу

К колонке можно обратиться по индексу: ТЗ.Колонки[0]. Проверка существования по индексу сводится к сравнению с количеством: Если ТЗ.Колонки.Количество() > 2 Тогда — колонка с индексом 2 существует. На практике индексы применяют редко: порядок колонок меняется при редактировании кода и при загрузке данных, поэтому код на индексах хрупкий.

Сравнение вариантов

Колонки.Найти(имя)

Основной способ: быстро, читаемо, нечувствителен к регистру. Подходит для точного имени колонки.

Перебор коллекции

Нужен при поиске по подстроке, типу или другим свойствам колонки. Медленнее и многословнее.

Обращение по индексу

Только когда порядок колонок гарантирован. Хрупко при изменении структуры таблицы.

Типичные ошибки при проверке колонок

Самая частая ошибка — проверять наличие колонки попыткой обращения к ней в строке. Конструкция Строка.Сумма при отсутствии колонки вызывает исключение, а не возвращает Неопределено. Перехват через Попытка...Исключение работает, но это медленно и маскирует реальные проблемы структуры данных.

Вторая распространённая ошибка — путать имя колонки и её заголовок. Если колонка создана кодом ТЗ.Колонки.Добавить("Сумма"), а в файле-источнике она называлась «Сумма документа», поиск по заголовку ничего не даст. Метод Найти() работает только с именем.

Третья группа ошибок связана с динамически формируемыми таблицами. Результат запроса Запрос.Выполнить().Выгрузить() содержит только те колонки, которые есть в выборке. Если в запросе используется левое соединение или условные поля, разработчик может ожидать колонку, которой в выгрузке нет. Проверка через Найти() перед обращением обязательна в таких сценариях.

Типичные ошибки
01
Обращение Строка.ИмяКолонки без проверки — при отсутствии колонки код падает с исключением
02
Поиск по заголовку колонки вместо имени — Найти() работает только с именем
03
Проверка через Попытка/Исключение — медленно и скрывает ошибки структуры данных
04
Использование индексов колонок — ломается при любом изменении порядка колонок
05
Отсутствие проверки таблицы на Неопределено перед обращением к Колонки

Когда таблица значений приходит из внешнего источника

При загрузке данных из Excel, CSV или через COM-соединение структура таблицы не гарантирована. Пользователь мог переименовать колонку в файле, удалить её или добавить лишнюю. В таких сценариях проверка наличия колонок — не опция, а обязательный этап валидации входных данных.

Рекомендуемый порядок: сразу после формирования таблицы проверить все обязательные колонки и, если хотя бы одной нет, прекратить обработку с понятным сообщением пользователю. Это лучше, чем падение в середине цикла после частичной записи данных в базу.

Если обработка уже начала записывать данные, а структура оказалась неверной, последствия зависят от того, использовалась ли транзакция. Загрузку, которая пишет в информационную базу, следует оборачивать в транзакцию (НачатьТранзакцию() / ЗафиксироватьТранзакцию() / ОтменитьТранзакцию()), чтобы при ошибке структуры откатить все изменения целиком.

Альтернативы: когда таблицу значений лучше заменить

Если проверок структуры становится слишком много, это признак того, что таблица значений — не лучший инструмент для задачи. Когда данные нужны только для чтения и фильтрации, выгоднее оставить их в результате запроса и работать через выборку: состав полей там фиксирован текстом запроса.

Для передачи небольшого набора именованных значений вместо таблицы из одной строки подойдёт структура. У структуры есть метод Свойство("Имя", Значение), который возвращает Истина, если свойство есть, и записывает его значение в переменную — встроенный аналог проверки наличия колонки:

Значение = Неопределено;

Если СтруктураДанных.Свойство("Сумма", Значение) Тогда

// свойство есть, значение получено

КонецЕсли;

Если же таблица значений используется как источник данных формы (динамический список, табличное поле), проверку колонок стоит выполнять на этапе формирования таблицы, а не в момент отрисовки — иначе ошибки всплывут у пользователя в интерфейсе.

В длинных обработках загрузки удобно в начале сформировать соответствие: ключ — имя обязательной колонки, значение — результат Найти(). Дальше в коде вместо повторных поисков используется готовое соответствие, что упрощает чтение и немного ускоряет работу на больших циклах.
ПЗ
Практическое замечание

Как проверить результат и убедиться в корректности кода

После внедрения проверки протестируйте оба сценария: с существующей колонкой и без неё. Второй сценарий часто забывают — в результате ветка «колонки нет» содержит опечатку и падает именно тогда, когда должна сработать защита.

Для отладки структуры таблицы удобно вывести список колонок в журнал регистрации или в сообщения:

Для Каждого Колонка Из ТЗ.Колонки Цикл

Сообщить(Колонка.Имя + " (" + Колонка.ТипЗначения + ")");

КонецЦикла;

В управляемых формах, где таблица значений является реквизитом формы, структуру можно посмотреть через отладчик: остановитесь на точке останова и разверните объект таблицы — коллекция Колонки покажет все имена и типы. Это быстрее, чем добавлять отладочные сообщения.

Контрольные точки

Как проверить результат

Вызов Найти() с существующим именем
Норма

Возвращает объект колонки, условие срабатывает

Тревожный признак

Возвращает Неопределено — проверьте имя и регистр

Вызов Найти() с отсутствующим именем
Норма

Возвращает Неопределено, срабатывает ветка Иначе

Тревожный признак

Исключение или падение — значит, где-то обращение идёт напрямую

Обращение к строке таблицы после проверки
Норма

Значение читается без ошибок

Тревожный признак

Ошибка «Поле объекта не обнаружено» — колонка не добавлена

Частые вопросы

Чувствителен ли поиск колонки к регистру букв?

Нет, метод Колонки.Найти() ищет без учёта регистра: «Сумма», «СУММА» и «сумма» найдут одну и ту же колонку. Тем не менее в коде лучше использовать то написание, в котором колонка создавалась, — это упрощает поиск по тексту модуля.

Что вернёт Найти(), если колонки нет?

Метод вернёт значение Неопределено. Исключения не возникает, поэтому Найти() безопасно вызывать без Попытка/Исключение для любых имён.

Как проверить наличие колонки у пустой таблицы без строк?

Точно так же — через ТЗ.Колонки.Найти("Имя"). Колонки существуют независимо от наличия строк: таблица может содержать ноль строк, но иметь полностью описанную структуру колонок.

Можно ли проверить колонку в табличной части документа так же?

У табличной части нет коллекции Колонки — это другой тип объекта. Состав полей табличной части определяется метаданными документа. Для проверки используют Метаданные.Документы[Имя].ТабличныеЧасти[ИмяТЧ].Реквизиты.Найти("ИмяРеквизита") или обращение через выгрузку табличной части в таблицу значений методом Выгрузить().

Что быстрее: Найти() или перебор коллекции?

Для точного совпадения имени — Найти(): метод реализован на уровне платформы и не требует цикла во встроенном языке. Перебор оправдан только тогда, когда условие поиска сложнее точного имени, например сравнение по типу значения или подстроке.

Как узнать тип данных колонки после проверки её существования?

Метод Найти() возвращает объект КолонкаТаблицыЗначений, у которого есть свойство ТипЗначения. Сохраните результат в переменную и прочитайте свойство: это описание типов, которое можно сравнить с ожидаемым через метод СодержитТип().

Итог

Что важно запомнить

Наличие колонки проверяется через ТЗ.Колонки.Найти("Имя"): результат отличный от Неопределено означает, что колонка есть. Поиск идёт по имени, а не по заголовку, и нечувствителен к регистру. Перед обращением к колонке в строках таблицы проверяйте её существование, а при загрузке внешних данных валидируйте все обязательные колонки до начала записи в базу.