Колонки таблицы значений 1С задают структуру данных: имя поля, допустимые типы, заголовок и ширину. Коллекция доступна через свойство Колонки и имеет собственные методы: Добавить, Вставить, Найти, Удалить, Индекс, Количество. От того, как созданы колонки, зависит, что лежит в пустых ячейках, примет ли таблицу запрос и сойдутся ли суммы.
Примеры написаны для платформы 8.3. Таблица значений доступна только на сервере и в толстом клиенте, поэтому в модуле управляемой формы код размещают в процедурах с директивой &НаСервереБезКонтекста или &НаСервере. Работа со строками таблицы разобрана в статье о таблице значений 1С, здесь — только колонки.
Синтаксис: Колонки.Добавить(Имя, Тип, Заголовок, Ширина). Метод ставит колонку в конец и возвращает объект КолонкаТаблицыЗначений. Все его параметры необязательные, но тип стоит указывать всегда. Колонки.Вставить(Индекс, Имя, Тип, Заголовок, Ширина) работает так же, только ставит колонку в заданную позицию. Нумерация колонок начинается с нуля.
&НаСервереБезКонтекста
Функция НоваяТаблицаТоваров()
Товары = Новый ТаблицаЗначений;
// Ссылка на справочник: такой тип должен быть в конфигурации
Товары.Колонки.Добавить("Номенклатура",
Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "Товар", 40);
// Строка переменной длины, не больше 25 символов
Товары.Колонки.Добавить("Артикул",
Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(25, ДопустимаяДлина.Переменная)),
"Артикул", 15);
// Число: 15 разрядов, из них 3 после запятой, без отрицательных значений
Товары.Колонки.Добавить("Количество",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3, ДопустимыйЗнак.Неотрицательный)),
"Кол-во", 10);
Товары.Колонки.Добавить("Сумма",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)), "Сумма", 12);
// Дата без времени
Товары.Колонки.Добавить("ДатаОтгрузки",
Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)), "Отгрузка", 10);
Товары.Колонки.Добавить("Отгружено", Новый ОписаниеТипов("Булево"), "Отгружено", 8);
// Вставка на первое место: индекс 0
Товары.Колонки.Вставить(0, "НомерСтроки",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(5, 0)), "№", 4);
// Заголовок и ширину можно поменять и после добавления
КолонкаСумма = Товары.Колонки.Найти("Сумма");
КолонкаСумма.Заголовок = "Сумма с НДС, руб.";
КолонкаСумма.Ширина = 14;
Возврат Товары;
КонецФункции
ОписаниеТипов передаются по позициям: второй параметр — для чисел, третий — для строк, четвёртый — для дат. Ненужную позицию оставляют пустой между запятыми.КвалификаторыЧисла(15, 3, ДопустимыйЗнак.Неотрицательный) — 15 разрядов, из них 3 дробных, минус запрещён.КвалификаторыДаты(ЧастиДаты.Дата) хранит дату без времени, для даты со временем нужен ЧастиДаты.ДатаВремя.ВыбратьСтроку. В управляемой форме заголовки берутся из реквизита формы.Вставить(0, ...) ставит «НомерСтроки» первой, остальные колонки сдвигаются вправо.Колонка, добавленная без второго параметра, принимает значения любого типа. Для черновика это удобно, но последствий три: в новой строке ячейка содержит Неопределено, записанное значение ни к чему не приводится, а запрос не примет такую таблицу параметром. Что лежит в ячейке новой строки:
| Тип колонки | Значение в новой строке |
|---|---|
| не задан | Неопределено |
| Число | 0 |
| Строка | пустая строка |
| Дата | пустая дата '00010101' |
| Булево | Ложь |
| СправочникСсылка.Номенклатура | пустая ссылка |
| составной тип | Неопределено |
&НаСервереБезКонтекста
Процедура СравнитьКолонкиСТипомИБезТипа()
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("СуммаБезТипа");
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));
Таблица.Колонки.Добавить("Код", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(5)));
// Составной тип из массива: у числа и строки свои квалификаторы
Типы = Новый Массив;
Типы.Добавить(Тип("Число"));
Типы.Добавить(Тип("Строка"));
Таблица.Колонки.Добавить("Значение",
Новый ОписаниеТипов(Типы, Новый КвалификаторыЧисла(10, 0), Новый КвалификаторыСтроки(20)));
// Тип и квалификаторы как у реквизита справочника
Таблица.Колонки.Добавить("Артикул",
Метаданные.Справочники.Номенклатура.Реквизиты.Артикул.Тип);
НоваяСтрока = Таблица.Добавить();
ПустоБезТипа = (НоваяСтрока.СуммаБезТипа = Неопределено); // Истина
ПустоСТипом = (НоваяСтрока.Сумма = 0); // Истина
НоваяСтрока.Код = "1234567";
Сообщить(НоваяСтрока.Код); // 12345: значение приведено к длине колонки
// Тип колонки читается через свойство ТипЗначения
ТипСуммы = Таблица.Колонки.Сумма.ТипЗначения;
ЭтоЧисло = ТипСуммы.СодержитТип(Тип("Число")); // Истина
Дробных = ТипСуммы.КвалификаторыЧисла.РазрядностьДробнойЧасти; // 2
// У колонки без типа массив типов пуст
БезТипа = (Таблица.Колонки.СуммаБезТипа.ТипЗначения.Типы().Количество() = 0); // Истина
КонецПроцедуры
Тип или перечисляют строкой через запятую: "СправочникСсылка.Контрагенты, СправочникСсылка.ФизическиеЛица".Реквизиты.Артикул.Тип возвращает ОписаниеТипов реквизита вместе с квалификаторами. Колонка получится той же длины, и при записи в объект ничего не обрежется.ТипЗначения — только для чтения. Тип проверяют через СодержитТип, а пустой массив Типы() означает колонку без типа.Итог или Свернуть, тоже типизируйте как Число: пустые ячейки станут нулями. В колонке без типа могут оказаться Неопределено и строки из файла, и итог перестанет совпадать с ожидаемым.Наличие колонки проверяют методом Колонки.Найти(Имя): он возвращает колонку или Неопределено и не вызывает исключения. Перебор — циклом Для Каждого по коллекции Колонки или по индексу от 0 до Количество() - 1.
// Возвращает колонку по имени; если её нет — добавляет
&НаСервереБезКонтекста
Функция КолонкаПоИмени(Таблица, Имя, ОписаниеТипа)
Колонка = Таблица.Колонки.Найти(Имя);
Если Колонка = Неопределено Тогда
Колонка = Таблица.Колонки.Добавить(Имя, ОписаниеТипа);
КонецЕсли;
Возврат Колонка;
КонецФункции
// Имена колонок в порядке следования
&НаСервереБезКонтекста
Функция ИменаКолонок(Таблица)
Имена = Новый Массив;
Для Каждого Колонка Из Таблица.Колонки Цикл
Имена.Добавить(Колонка.Имя);
КонецЦикла;
Возврат Имена;
КонецФункции
&НаСервереБезКонтекста
Процедура ПроверитьСтруктуру(Таблица)
// Проверка наличия: Найти не вызывает исключения
Если Таблица.Колонки.Найти("Количество") = Неопределено Тогда
ВызватьИсключение "В таблице нет колонки ""Количество""";
КонецЕсли;
// Повторный вызов не создаст дубль
КолонкаПоИмени(Таблица, "Комментарий",
Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(200)));
// Обход по индексу, когда нужен номер колонки
Для Индекс = 0 По Таблица.Колонки.Количество() - 1 Цикл
Колонка = Таблица.Колонки[Индекс];
Сообщить(СтрШаблон("%1: %2 (%3)", Индекс, Колонка.Имя, Колонка.Заголовок));
КонецЦикла;
// "НомерСтроки, Номенклатура, Артикул, ..."
СписокКолонок = СтрСоединить(ИменаКолонок(Таблица), ", ");
Сообщить(СписокКолонок);
КонецПроцедуры
КолонкаПоИмени можно вызывать сколько угодно раз, а повторный Добавить с тем же именем вызвал бы исключение.Таблица.Колонки.Цена к несуществующей колонке тоже падает с ошибкой, поэтому для необязательных колонок — только Найти.СтрСоединить доступна с версии 8.3.6. Полученная строка подходит как список колонок для Скопировать, СкопироватьКолонки, Свернуть и ЗаполнитьЗначения.Свойство Имя доступно для записи, поэтому переименование — обычное присваивание. Колонки.Удалить принимает саму колонку, её индекс или имя. А вот ТипЗначения изменить нельзя: колонку с новым типом создают заново и переносят в неё данные.
// Меняет тип колонки, сохраняя позицию, заголовок, ширину и данные
&НаСервереБезКонтекста
Процедура ИзменитьТипКолонки(Таблица, ИмяКолонки, НовыйТип)
СтараяКолонка = Таблица.Колонки.Найти(ИмяКолонки);
Если СтараяКолонка = Неопределено Тогда
ВызватьИсключение СтрШаблон("Колонка %1 не найдена", ИмяКолонки);
КонецЕсли;
Значения = Таблица.ВыгрузитьКолонку(СтараяКолонка);
Для Индекс = 0 По Значения.ВГраница() Цикл
Значения[Индекс] = НовыйТип.ПривестиЗначение(Значения[Индекс]);
КонецЦикла;
Позиция = Таблица.Колонки.Индекс(СтараяКолонка);
НоваяКолонка = Таблица.Колонки.Вставить(Позиция, ИмяКолонки + "Новая", НовыйТип,
СтараяКолонка.Заголовок, СтараяКолонка.Ширина);
Таблица.ЗагрузитьКолонку(Значения, НоваяКолонка);
Таблица.Колонки.Удалить(СтараяКолонка);
НоваяКолонка.Имя = ИмяКолонки;
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ПереименоватьУдалитьТипизировать()
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Кол"); // без типа
Таблица.Колонки.Добавить("Служебная");
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Кол = 5;
Таблица.Добавить(); // во второй строке Кол = Неопределено
// Переименование: свойство Имя доступно для записи
Таблица.Колонки.Кол.Имя = "Количество";
// Удаление по имени; можно передать и индекс, и саму колонку
Таблица.Колонки.Удалить("Служебная");
ИзменитьТипКолонки(Таблица, "Количество",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Итого = Таблица.Итог("Количество"); // 5: пустая ячейка стала нулём
Сообщить(Итого);
КонецПроцедуры
ПривестиЗначение превращает Неопределено в значение по умолчанию нового типа: для числа это 0, для ссылки — пустая ссылка.ВыгрузитьКолонку(Колонка) возвращает массив значений колонки в порядке строк; колонку передают именем, индексом или объектом. ЗагрузитьКолонку(Массив, Колонка) делает обратное: раскладывает элементы массива по существующим строкам. Строки метод не добавляет, их создают заранее — так массив превращается в таблицу. Подробнее — в статье о преобразовании массива в таблицу значений.
// Массив значений -> таблица с одной типизированной колонкой
&НаСервереБезКонтекста
Функция ТаблицаИзМассива(Значения, ИмяКолонки, ОписаниеТипа)
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить(ИмяКолонки, ОписаниеТипа);
// ЗагрузитьКолонку не добавляет строки: создаём их заранее
Для Счетчик = 1 По Значения.Количество() Цикл
Таблица.Добавить();
КонецЦикла;
Таблица.ЗагрузитьКолонку(Значения, ИмяКолонки);
Возврат Таблица;
КонецФункции
// Ссылки, выделенные в списке формы, -> таблица для соединения в запросе
&НаСервереБезКонтекста
Функция ТаблицаВыделенных(ВыделенныеСсылки)
Возврат ТаблицаИзМассива(ВыделенныеСсылки, "Ссылка",
Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
КонецФункции
// Товары — таблица из первого листинга
&НаСервереБезКонтекста
Функция УникальнаяНоменклатура(Товары)
// Колонка -> массив, например для условия В (&Номенклатура) в запросе
ВсяНоменклатура = Товары.ВыгрузитьКолонку("Номенклатура");
// Без дублей: копия одной колонки + Свернуть, исходная таблица не меняется
Уникальные = Товары.Скопировать(, "Номенклатура");
Уникальные.Свернуть("Номенклатура");
БезДублей = Уникальные.ВыгрузитьКолонку("Номенклатура");
Сообщить(СтрШаблон("Строк: %1, разных товаров: %2",
ВсяНоменклатура.Количество(), БезДублей.Количество()));
Возврат БезДублей;
КонецФункции
ВыгрузитьКолонку — копия: его изменения на таблицу не влияют.ТаблицаИзМассива количество строк равно числу элементов массива, поэтому каждое значение попадает в свою строку.Скопировать одной колонки и Свернуть по ней же дают список без повторов.Пустая таблица с той же структурой нужна для накопления результата, для шаблона параметра запроса или для второй таблицы при сравнении. СкопироватьКолонки создаёт новую таблицу с колонками исходной и без строк; необязательный параметр ограничивает список колонок. Скопировать(Строки, Колонки) копирует и данные: все строки, массив строк или строки по отбору-структуре.
// Строки с количеством не меньше заданного — в таблицу той же структуры
&НаСервереБезКонтекста
Функция КрупныеПозиции(Товары, МинимальноеКоличество)
Результат = Товары.СкопироватьКолонки();
Для Каждого СтрокаТоваров Из Товары Цикл
Если СтрокаТоваров.Количество >= МинимальноеКоличество Тогда
ЗаполнитьЗначенияСвойств(Результат.Добавить(), СтрокаТоваров);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
// Копия со строками, но без перечисленных колонок: "Комментарий, Служебная"
&НаСервереБезКонтекста
Функция КопияБезКолонок(Таблица, ИсключаемыеКолонки)
Исключаемые = Новый Массив;
Для Каждого Имя Из СтрРазделить(ИсключаемыеКолонки, ",", Ложь) Цикл
Исключаемые.Добавить(ВРег(СокрЛП(Имя)));
КонецЦикла;
Оставить = Новый Массив;
Для Каждого Колонка Из Таблица.Колонки Цикл
Если Исключаемые.Найти(ВРег(Колонка.Имя)) = Неопределено Тогда
Оставить.Добавить(Колонка.Имя);
КонецЕсли;
КонецЦикла;
Возврат Таблица.Скопировать(, СтрСоединить(Оставить, ","));
КонецФункции
&НаСервереБезКонтекста
Процедура ВариантыКопирования(Товары)
// Только структура выбранных колонок
Шаблон = Товары.СкопироватьКолонки("Номенклатура, Количество");
// Только структура через Скопировать: пустой массив строк
ПустаяКопия = Товары.Скопировать(Новый Массив);
// Выбранные колонки вместе со строками
Краткая = Товары.Скопировать(, "Номенклатура, Количество");
// Строки по отбору, все колонки
НеОтгружено = Товары.Скопировать(Новый Структура("Отгружено", Ложь));
КонецПроцедуры
СкопироватьКолонки() лучше пары Скопировать() и Очистить(): строки вообще не копируются, что заметно на больших таблицах.КопияБезКолонок сравнивает имена в верхнем регистре, потому что имена колонок к регистру не чувствительны.ВыгрузитьКолонки(): пустая таблица значений с колонками табличной части.Таблицу передают в запрос параметром и первым делом помещают во временную таблицу. Временная таблица создаётся в СУБД, тип каждого поля должен быть известен заранее, и платформа берёт его из ТипЗначения колонки. Отсюда правила:
Скопировать(, "Кол1, Кол2").// Проверка перед передачей таблицы в запрос
&НаСервереБезКонтекста
Процедура ПроверитьКолонкиДляЗапроса(Таблица)
Для Каждого Колонка Из Таблица.Колонки Цикл
ТипКолонки = Колонка.ТипЗначения;
Если ТипКолонки.Типы().Количество() = 0 Тогда
ВызватьИсключение СтрШаблон("Колонка %1 без типа", Колонка.Имя);
КонецЕсли;
Если ТипКолонки.СодержитТип(Тип("Строка"))
И ТипКолонки.КвалификаторыСтроки.Длина = 0 Тогда
ВызватьИсключение СтрШаблон("Колонка %1: строка неограниченной длины", Колонка.Имя);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
// Строки загрузки сопоставляются с номенклатурой по артикулу
&НаСервереБезКонтекста
Функция СопоставитьПоАртикулу(Загрузка)
ПроверитьКолонкиДляЗапроса(Загрузка);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Т.Артикул КАК Артикул,
| Т.Количество КАК Количество
|ПОМЕСТИТЬ ВТ_Загрузка
|ИЗ
| &Загрузка КАК Т
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_Загрузка.Артикул КАК Артикул,
| ЕСТЬNULL(Номенклатура.Ссылка, ЗНАЧЕНИЕ(Справочник.Номенклатура.ПустаяСсылка)) КАК Номенклатура,
| ВТ_Загрузка.Количество КАК Количество
|ИЗ
| ВТ_Загрузка КАК ВТ_Загрузка
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Номенклатура
| ПО ВТ_Загрузка.Артикул = Номенклатура.Артикул";
Запрос.УстановитьПараметр("Загрузка", Загрузка);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
&НаСервереБезКонтекста
Функция ЗагрузкаИзФайла()
Загрузка = Новый ТаблицаЗначений;
Загрузка.Колонки.Добавить("Артикул",
Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50)));
Загрузка.Колонки.Добавить("Количество",
Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
// В реальной обработке строки заполняются из файла
НоваяСтрока = Загрузка.Добавить();
НоваяСтрока.Артикул = "А-1001";
НоваяСтрока.Количество = 12;
Возврат СопоставитьПоАртикулу(Загрузка);
КонецФункции
ПроверитьКолонкиДляЗапроса ловит обе частые проблемы до выполнения запроса и называет колонку — такое сообщение понятнее системного.ВТ_Загрузка, второй соединяет её со справочником. Менеджер временных таблиц не нужен: пакет выполняется одним вызовом.ПО ВТ_Загрузка.Артикул = Номенклатура.Артикул возможно, потому что у колонки «Артикул» задана длина 50.Запрос.Выполнить().Выгрузить() и ТабличнаяЧасть.Выгрузить() уже типизированы, их можно передавать в запрос без подготовки.Колонки.Найти.ОписаниеТипов при создании или смените тип процедурой ИзменитьТипКолонки.КвалификаторыСтроки попала в условие соединения или ГДЕ. Укажите длину строки.Неопределено. Типизируйте колонку как Число, и пустые ячейки станут нулями.Найти, а текст для пользователя пишите в заголовок.Напрямую никак: ТипЗначения доступен только для чтения. Вставьте рядом колонку с нужным типом, перенесите значения через ВыгрузитьКолонку и ЗагрузитьКолонку, удалите старую и дайте новой её имя — как в процедуре ИзменитьТипКолонки.
Колонки.Найти("Имя") ищет колонку по имени и возвращает КолонкаТаблицыЗначений или Неопределено. Таблица.Найти(Значение, "Колонка1, Колонка2") ищет значение в строках и возвращает первую подходящую строку.
Нет. Имя колонки подчиняется правилам идентификатора: буквы, цифры и подчёркивание, первой не может быть цифра. Назовите колонку ЦенаСНДС, а текст с пробелами передайте третьим параметром, в заголовок.
Да. Скопировать и СкопироватьКолонки переносят колонки вместе с описанием типов, поэтому шаблон, сделанный из типизированной таблицы, тоже типизирован.
Если нужна загрузка из Excel с сопоставлением колонок, проверкой типов и записью в документы, её быстрее заказать как разработку обработки 1С под вашу конфигурацию. Опишите задачу и приложите пример файла на странице «Разместить задание» — исполнители предложат сроки и цену.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.