Доброго дня.

Я ищу наставника, который готов помощь по моим вопросам 1с.

Мне нужно
1. Хотелось бы узнать, как можно оптимизировать код (именно с пояснениями, а не просто переписать код).
2. Посоветовать хорошую программу для обучения.
3. Я вижу свои пробелы в знании 1с и хотелось бы получить консультации только по интересующим вопросам.

Конечно же это за оплату.
Может быть есть у кого-то есть опыт программирования в 1с и желание быть наставником, то прошу Вас написать мне в личное сообщение для дальнейшего обсуждения.
---
При оптимизации кода важно понимать, что в итоге/какую именно оптимизацию вы хотите получить и за счет чего, а то может оказаться так, что и оптимизировать нечего.

Основные принципы оптимизации - сокращать количество вызовов функций/процедур/получения значений из БД, избавление от запросов в цикле.
---
2. Я бы сделала так
на клиенте
вызвала бы функцию реквизит номенклатуры
а на сервере делала бы запрос.
Самое главное не делать это в цикле для каждой строки ТЧ.
Далее, определить объем данных на форме. Если форма не "тяжелая" (не много реквизитов и табличных частей и в ТЧ не много колонок), то можно просто сделать контекстный серверный вызов, в котором запросом получить нужные данные и заполнить нужную колонку ТЧ.
Вот если форма тяжелая и контекстный вызов делается долго и требует оптимизации, только тогда ищется другой способ. Не раньше. Не стоит все оптимизировать заранее усложняя код.
Как вариант, можно выбрать ссылки номенклатур и его передать на сервер без контекста. Но тогда придется получать нужные данные по цене и заполнять на клиенте.
---
При оптимизации кода важно понимать, что в итоге/какую именно оптимизацию вы хотите получить и за счет чего, а то может оказаться так, что и оптимизировать нечего.

Основные принципы оптимизации - сокращать количество вызовов функций/процедур/получения значений из БД, избавление от запросов в цикле.
---
)))
На сайте: 11 лет 11 месяцев

PS Спросить на форуме - бесплатно, для всего остального есть мастеркард)
---
Да, я давно на этот форуме и по многим вопросам он мне сильно помог.
Я читаю различные материалы, ищу решения возникающих проблем.

Только бывает так, что не получается или получается не совсем оптимально.
Я не отказываюсь оплатить услуги и я ищу такого человека, который готов лично со мной позаниматься 1с 8.3.
---
в качестве обучения возьмите какой-то кусок кода, который по вашему мнению не является оптимальным, разместите его на форуме, можно даже в этой теме, коллективный разум вам даст некие советы по оптимизации конкретно этого кода.

Далее ваша задача интерполировать полученные знания на остальные случаи.
---
Что не так в этом куске кода?)

```1c
    &НаКлиенте
    Процедура Один()

    Товары = Документ.Товары;

    Для Каждого Стр ИЗ Товары Цикл

    Цена = РеквизитНоменклатуры(Стр.Номенклатура, "Цена");

    КонецЦикла;

    КонецПроцедуры

    &НаСервере
    Процедура РеквизитНоменклатуры(Номенклатура, ИмяРеквизита)

    Возврат Номенклатура[ИмяРеквизита];

    Конецпроцдуры
```
---
Как минимум:
1. Цена хранится в справочнике, в виде реквизита.
2. цикличное получения значения реквизита = запрос в цикле

:)
---
дополню )
1. Циклический контекстный вызов сервера. Данные желательно получать по возможности одним вызовом. И если возможно, то не контекстным.
2. Переменная Цена переназначается и нигде больше не используется )
---
(8)
Ну да ну да, вы ж тут хотели научится оптимизировать...
---
так это надо от ТС увидеть код и обоснование его неоптимальности.

Дать некий "сферический код в вакууме" и попросить объяснить в чем его неоптимальность - такое себе, человек может еще и не знает, на что обращать внимание при поиске неоптимальных участков кода.
---
2. Переменная Цена переназначается и нигде больше не используется )
Я как будто c++ код компилил сейчас...
---
С практической точки зрения код бесполезен, он ничего не делает полезного. ;) И вот не понятно - Документ.Товары - точно на клиенте? ;)

(6) Конецпроцдуры ошибочки типа описочки
---
И вот не понятно - Документ.Товары - точно на клиенте? ;)

Вполне себе, только для чего - не понятно абсолютно, т.к. Документ.Товары(при условии, что Документ - это основной реквизит формы объекта) доступен на клиенте напрямую и нет особой необходимости присваивать это какой-либо переменной.
---
Я никогда не делала возврат из процедуры, только из функции, даже и не знаю, можно ли так делать.
Конечно же нельзя. Но эта ошибка выскочит при сохранении конфигурации. Обращение к процедуре как к функции.
---
Но почему же? Когда человек ищет ошибку, он думает, происходит мыслительные процессы. Когда ему просто аргументировать, он это просто примет как факт. Когда он подумает, и ему потом аргументируют - то будет и то и то. Так что не вижу в таком методе что то плохое)

(12) Мы говорим об абстрактном куске кода, придуманным за 10 секунд) Его практическое значение - показать пример куска кода)

(13) Да, процедура не возвращает значения) Но это была лишь крохотная ошибка)
---
2. Я бы сделала так
на клиенте
вызвала бы функцию реквизит номенклатуры
а на сервере делала бы запрос.
Самое главное не делать это в цикле для каждой строки ТЧ.
Далее, определить объем данных на форме. Если форма не "тяжелая" (не много реквизитов и табличных частей и в ТЧ не много колонок), то можно просто сделать контекстный серверный вызов, в котором запросом получить нужные данные и заполнить нужную колонку ТЧ.
Вот если форма тяжелая и контекстный вызов делается долго и требует оптимизации, только тогда ищется другой способ. Не раньше. Не стоит все оптимизировать заранее усложняя код.
Как вариант, можно выбрать ссылки номенклатур и его передать на сервер без контекста. Но тогда придется получать нужные данные по цене и заполнять на клиенте.
---
```1c
    Выборка = Запрос.Выполнить().Выбрать();

    Пока Выборка.СледующийПоЗначениюПоля("ЛС") Цикл

    //Если начало периода не пустая дата
    Если Выборка.НачалоПериода <>Дата(1,1,1) Тогда

    Док = Документы.КУ_Претензия.СоздатьДокумент();
    ДОК.Дата = ТекущаяДата();
    Док.Собственник = Выборка.ОтветственныйСобственник;

    //Чтобы период был равен периоду задолженности, а не весь период
    Док.НачалоПериода = Мин(Выборка.НачалоПериода) ;
    Док.КонецПериода = Макс(Выборка.КонецПериода );
    //
    Док.Организация = Организация;
    ДОк.Ответственный = Справочники.Пользователи.НайтиПоНаименованию(имяПользователя());
    ДОк.Состояние = СостояниеДОК;

    Если Выборка.ДатаЗакрытия<>Дата(1, 1, 1) Тогда
    Док.Комментарий = Строка("Закрытые лицевые счета!!!! от "+Выборка.ДатаЗакрытия);
    КонецЕсли;//Выборка.ДатаЗакрытия<> ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0) Тогда

    Пока Выборка.Следующий() Цикл
    Если Выборка.ПериодВзаиморасчетов <=Выборка.КонецПериода Тогда
    строкаТч = Док.Задолженность.Добавить();
    СтрокаТЧ.ЛицевойСчет = Выборка.ЛС;
    строкаТч.помещение = Выборка.Помещение;
    СтрокаТЧ.ВидУслуги = Выборка.ВидУслуги;
    СтрокаТЧ.ПериодВзаиморасчетов=Выборка.ПериодВзаиморасчетов;
    СтрокаТЧ.СуммаВсего = Выборка.СуммаВсего;
    СтрокаТЧ.СуммаДолга = Выборка.СуммаДолга;
    СтрокаТЧ.СуммаПени = Выборка.СуммаПени;
    //Док.Записать();

    КонецЕсли; // Выборка.ПериодВзаиморасчетов >=Выборка.НачалоПериода Тогда

    КонецЦикла; //Выборка.Следующий() Цикл

    Док.Записать();

    КонецЕсли; //Выборка.НачалоПериода <>Дата(1,1,1,) Тогда

    КонецЦикла; //Пока Выборка.Следующий() Цикл
```

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

Это всё в цикле.

Подскажите пожалуйста, это верное и оптимальное решение или у Вас есть предложения, как улучшить??

Дополню ещё.

Если ещё и другой документ, который создаётся на основании первого документа.
С такими же полями и с такой же самое табличной частью.
И как можно в 1 запросе и цикле, в зависимости от условий создать и заполнить 2 документа.

Как можно сделать этот цикл
---
1. Вы в каждой строке проверяете, что Начало периода не пустая дата, это условие можно перенести в запрос, чтобы он возвращал только нужные данные.
2. Вы ищите пользователя в цикле, его можно искать перед циклом, 1 раз, а потом просто присваивать.
3. Я бы в запрос добавил итоги по ЛС, чтобы делать обход результата запроса с группировкой, имхо, это более читаемо.
---
Sashares,

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

Пустая дата- понятно, поправлю.

А вот по итогам по ЛС и обход по результатам группировок- не совсем понятно для чего это нужно.
---
А вот по итогам по ЛС и обход по результатам группировок- не совсем понятно для чего это нужно.

Изменить текст запроса - добавить секцию ИТОГИ, изменить обработку результата запроса.

Например:

```1c
    //{{КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
    // Данный фрагмент построен конструктором.
    // При повторном использовании конструктора, внесенные вручную изменения будут утеряны!!!

    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | ЛицевыеСчета.Ссылка КАК ЛицевойСчет,
    | ЛицевыеСчетаДополнительныеРеквизиты.НомерСтроки КАК НомерСтроки,
    | ЛицевыеСчетаДополнительныеРеквизиты.Свойство КАК Свойство,
    | ЛицевыеСчетаДополнительныеРеквизиты.Значение КАК Значение,
    | ЛицевыеСчетаДополнительныеРеквизиты.ТекстоваяСтрока КАК ТекстоваяСтрока
    |ИЗ
    | Справочник.ЛицевыеСчета КАК ЛицевыеСчета
    | ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ЛицевыеСчета.ДополнительныеРеквизиты КАК ЛицевыеСчетаДополнительныеРеквизиты
    | ПО (ЛицевыеСчетаДополнительныеРеквизиты.Ссылка = ЛицевыеСчета.Ссылка)
    |ИТОГИ ПО
    | ЛицевойСчет";

    РезультатЗапроса = Запрос.Выполнить();

    ВыборкаСсылка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

    Пока ВыборкаСсылка.Следующий() Цикл
    // тут в каждой строке выборки будет свой лицевой счет, остальные поля выборки в большинстве случаев будут не заполнены
    // количество строк в выборке = количеству лицевых счетов
    ВыборкаДетальныеЗаписи = ВыборкаСсылка.Выбрать();

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    //тут будут детальные строки по текущему лицевому счету, который в ВыборкаСсылка.Лицевой счет
    КонецЦикла;
    КонецЦикла;

    //}}КОНСТРУКТОР_ЗАПРОСА_С_ОБРАБОТКОЙ_РЕЗУЛЬТАТА
```
---
```1c
    Пока Выборка.СледующийПоЗначениюПоля("ЛС") Цикл
    Пока Выборка.Следующий() Цикл
```

Чем по оптимальности отличается Ваш код от моего??
---
Дело не в оптимальности, дело в читаемости.
Например, если записать весь код в 1 строку, он будет работать быстрее.
Но это же не означает, что стоит так делать.
---
Попробую реализовать предложенный Вами способ.
---
При использовании итогов в запросе, в запрос можно добавить Минимум и Максимум для полей НачалоПериода и ОкончаниеПериода - и в них будет как раз минимальное и максимальное значение полей по каждому лицевому счету.

```1c
    ИТОГИ
    МАКСИМУМ(КонецПериода),
    МИНИМУМ(НачалоПериода)
    ПО
    ЛицевойСчет
```

И в выборке по лицевым счетам эти поля будут заполнены.
---
Вот кстати тоже момент, где я пока что не нашла хорошего решения, я по этому поводу спрашивала как-то на форуме..

начало периода- это такое поле, которое получается из условий.
1. если не было док. претензия, то тогда с начала задолженности.
2 если есть док. претензия, то тогда начало периода = последний документ Претензия.КонецПериода + 1 день.

```1c
    Если Объект.Задолженность.Количество()<>0 Тогда
    Для каждого Стр Из Объект.Задолженность Цикл
    //Чтобы период был равен периоду задолженности, а не весь период
    Запрос.УстановитьПараметр("НачалоПериода", Стр.НачалоПериода);
    //Ставим конец периода текущую дату потому, что ЛС мог оплатить
    Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДата()));
    КонецЦикла; //Для каждого Стр Из ТаблицаДолг Цикл
    КонецЕсли; //Объект.Задолженность.Количество()<>0 Тогда
```

Пользователи вручную создают и заполняют документы претензия и исковое заявление.
Я сделала этот код ради интереса, но им всё равно никто не пользуется.
---
Если можно делать запросом, делайте именно им.
---
тут цикл правомерен, так как по другому и не получится. Мы не говорили, что сам факт наличия цикла это плохо.

//Чтобы период был равен периоду задолженности, а не весь период
            Док.НачалоПериода = Мин(Выборка.НачалоПериода) ;
            Док.КонецПериода = Макс(Выборка.КонецПериода );
Вот этот код совсем не понятно, зачем в нем функции Мин и Макс? Они ничего не делают.

Далее, заполнение табличной части можно упростить, если в запросе получать представления имен полей такое же как в ТЧ.
Тогда можно использовать так:

```1c
    Пока Выборка.Следующий() Цикл
    Если Выборка.ПериодВзаиморасчетов <=Выборка.КонецПериода Тогда
    строкаТч = Док.Задолженность.Добавить();
    ЗаполнитьЗначенияСвойств(СтрокаТЧ, Выборка);
    КонецЕсли; // Выборка.ПериодВзаиморасчетов >=Выборка.НачалоПериода Тогда

    КонецЦикла; //Выборка.Следующий() Цикл
```

Это то сразу бросилось в глаза.
---
Вот этот код совсем не понятно, зачем в нем функции Мин и Макс? Они ничего не делают.

Далее, заполнение табличной части можно упростить, если в запросе получать представления имен полей такое же как в ТЧ.
Тогда можно использовать так:
            Пока Выборка.Следующий() Цикл
                Если Выборка.ПериодВзаиморасчетов =Выборка.НачалоПериода Тогда

            КонецЦикла; //Выборка.Следующий() Цикл

Благодарю Вас за пояснение, поняла.
---
1.
```1c
    Справочники.Пользователи.НайтиПоНаименованию(имяПользователя())
```

вынесити за цикл, потому что получается запрос в цикле

2.
```1c
    Если Выборка.ПериодВзаиморасчетов <=Выборка.КонецПериода Тогда
    строкаТч = Док.Задолженность.Добавить();
    СтрокаТЧ.ЛицевойСчет = Выборка.ЛС;
    строкаТч.помещение = Выборка.Помещение;
    СтрокаТЧ.ВидУслуги = Выборка.ВидУслуги;
    СтрокаТЧ.ПериодВзаиморасчетов=Выборка.ПериодВзаиморасчетов;
    СтрокаТЧ.СуммаВсего = Выборка.СуммаВсего;
    СтрокаТЧ.СуммаДолга = Выборка.СуммаДолга;
    СтрокаТЧ.СуммаПени = Выборка.СуммаПени;
    //Док.Записать();
    КонецЕсли;
```

замените на

```1c
    Если Выборка.ПериодВзаиморасчетов <=Выборка.КонецПериода Тогда
    ЗаполнитьЗначенияСвойств(Док.Задолженность.Добавить(), Выборка);
    КонецЕсли;
```
---
Спасибо за замечания
---
ну и еще я бы посмотрел на запрос, т.к. им нужно максимально готовые данные выгребать из БД.
---
А как быть в таком случае.
Есть к примеру в выборке из запроса 100 различных строк, где есть сумма. Необходимо для каждой суммы сделать сумму прописью (обращение к функции числоПрописью)
Делаю так:

```1c
    Пока выборка.следующий () цикл
    суммаПрописью = числоПрописью(выборка.сумма);
    КонецЦикла;
```

Т.е получается, что каждый раз в цикле идёт обращение к функции.
---
именно в таком виде код бессмыслен. суммаПрописью тупо перезаписывается )
Но если о самой технике получения числа прописью в цикле для каждой строки выборки, то это нормально. По другому не сделать.
Тут не идет получение данных из базы данных в цикле и не вызов сервера с клиента в цикле. Именно об этом и речь. Сам по себе цикл это нормально. Просто нужно понимать, когда его не желательно использовать.
---
Далее это суммаПрописью попадает в печатную форму.

Понятно, благодарю Вас за ответ.
---
Поддержу (51) и добавлю:
1. Плохо - выполнение запросов цикле (обращение к БД, нагрузка SQL). Или обращение к функциям и процедурам, которые используют обращение к БД.
2. Нормально - работа с циклами в оперативной памяти - один раз запросом получили данные из БД, они загрузились в оперативную память (выборка находится в ОЗУ), и тут их уже можно и нужно вертеть циклами (но с умом!).

И да, ваш код не имеет смысла.
---
```1c
    Пока выборка.следующий () цикл
    суммаПрописью = числоПрописью(выборка.сумма);

    //добавлю тут также
    ОбластьПечати.Параметры.СуммаПрописью = суммаПрописью;

    КонецЦикла;
```

Так имеет смысл?
---
Да (но при условии либо смены области, либо её вывода в результат:

```1c
    ОбластьПечати = Макет.ПолучитьОбласть(ИмяОбласти);
    Пока Выборка.Следующий () Цикл
    ОбластьПечати.Параметры.СуммаПрописью = ЧислоПрописью(Выборка.Сумма);
    ТабДок.Вывести(ОбластьПечати);
    КонецЦикла;
```

PS. Попытайтесь писать операторы с Большой Буквы. УНасТакПринято. ЭтоУважениеККоллегам.
---
Я стараюсь так и писать, сейчас просто с телефона пишу, поэтому не удобно всегда делать большие буквы.

У меня такой же рабочий код, как и в Вашем примере.
---
нет смысла создавать промежуточную переменную, если можно без нее и она больше не используется далее.
Заполнение параметров так же надежнее заполнять заполнением свойств. В запросе или макете даете сопоставимые имена и все параметры сразу заполняете по выборке. Так не будет ошибки времени выполнения. Максимум это данные не подставятся, но ошибка не выскочит.
---
Согласен, но в данном примере это вычисляемое поле (не СКД). Поэтому либо через прямое присвоение параметру значения функции, либо не через Выборку, а через ТЗ с добавлением колонки...
---
да, я не обратил внимание на получение числа прописью.
Но и даже в таком случае лучше создать Структуру с нужными ключами по параметрам печатной формы и заполнить через нее.
---
Если можно, поясните пожалуйста, как в ТЗ добавить колонку СуммаПрописью??
Как для всей Выборки из Запроса выполнить функцию ЧислоПрописью??
---
1. ТЗ.Колонки.Добавить("СуммаПрописью", Новый ОписаниеТипов("Строка"));
2. Никак. Здесь только перебор строк ТЗ или Выборки. Потому что в качестве параметра функции выступает конкретное число, которое вы сможете взять только из конкретной строки. Читаем СП.
---
Ясно, до этого значит я не так поняла Вас и не верно задала прошлый вопрос.
Пункт 1 я иногда так и делаю.
---
Подскажите пожалуйста, а как добавить колонки в ТЗ на форме (не является реквизитом обработки, данные заполняются из результатов запросов).
Пробую так

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

в таком случае ругается.

Я в запрос добавила пустую колонку.

```1c
    |0 КАК МоёЧисло,
```

В цикле по строкам ТЗ я редактирую эту колонку, таким образом работает.
---
Новый РеквизитФормы() - это если программно.
А в конструкторе - на самом реквизите есть пункт добавления подчиненных колонок к табличному реквизиту (не к элементу!)
---
Вы мне сегодня про заполнение ТЧ документа также подсказали.
В печатной форме я это уже раньше реализовала, а вот про заполнение ТЧ документа не знала.

Просто привела пример кода, где идёт получение ЧислоПрописью

P.s.

Спасибо Вам огромное за пояснения. Реально, перечитывая сообщения или когда необходима помощь, то именно такие подробные сообщения и помогают понять.
---
вот так можно было бы сделать, если данные из выборки нужно обрабатывать дополнительно. Параметров области может быть несколько. Указываем их при создании структуры.

```1c
    Пока выборка.следующий () цикл
    ПараметрыОбласти = Новый Структура("Парам1,Парам2,СуммаПрописью");
    ЗаполнитьЗначенияСвойств(ПараметрыОбласти, Выборка);
    ПараметрыОбласти["СуммаПрописью"] = числоПрописью(выборка.сумма);

    ОбластьПечати.Параметры.Заполнить(ПараметрыОбласти);
    ТабДок.Вывести(ОбластьПечати);

    КонецЦикла;
```

Если постобработка данных из выборки не нужна, то можно обойтись без структуры и заполняем параметры сразу из выборки.
---
Такой вариант кода, когда из Структуры заполняем Табличной Документ, то для меня эта новая информация.

Необходимо попробовать, как это будет работать.
---
К оптимизации нужно подходить с практической стороны.
Если код работает за приемлемое время и вы лучше его не напишите, то оптимизировать нечего.
А так обращайтесь, проконсультирую.
---
Почитайте книги по совершенному коду и рефакторингу. Тот же, Совершенный код (Макконнелл). Понятно, что там не про 1С. Но многое по полочкам разложится.
---
Забей. Оптимальный код - это гемор. Да и не нужен они никому толком.

Пример: можно загрузить список недействительных паспортов в базу 1С за 10 часов. Можно просто записать недействительные паспорта в 5000 файлов за 40 минут. Можно хитро загрузить их в 1С за 10 минут, но не в таблицу. От первого решения до третьего в части оптимизации прошло четыре года. Стоило? Может быть...

Забей.
---
А обновлять потом эти 5000 файлов как?
---
просто затираешь за те же 40 минут. По ним нет разностной копии - они валятся вперемешку.

Зы: в файловых потоках есть возможность дописать в конец файла. Очень быстро и просто.
---
Можно хитро загрузить их в 1С за 10 минут, но не в таблицу.
А куда?
---
Нуу.... В ХранилищеНастроек, например )))))
---
а сколько у Вас денег?
---
А у вас?
Если вы не хотите раскрывать особенности реализации, можно так и сказать, ваше дело.
Платить вам чисто из любопытства я не собираюсь.

Но тогда зачем тогда писать об этих ваших достижениях в каждой теме, не очень понятно. Неужели ради ЧСВ?
---
нет ручек - нет конфеток. Могу доступ к сервису дать для тестирования скорости
---
У меня нет задачи загрузки недействительных паспортов.
Поэтому и в доступе к сервису смысла нет.
Это был интерес о загрузке большого количества данных в базу, т.к. это довольно распространенная задача.
Если вы ничего по теме рассказать не можете, ок. Нет, так нет.
---
в жанном случае грузить это в базу долго, дорого и раьотает потом медленно.

А по поводу загрузки в базу, то если архитектура хотя бы третьей нормальной форме соответствует, то со скоростью можно работать.

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

Все задачи решаются очень большим количествлм методов, и большинство методов - правильные.
---
в жанном случае
Опечатка по Фрейду? В каком месте букву на д менять? )))
---
в одном))

А Фрейд в Жанном случае ни при чем.
---
truncate наше все ))
---
truncate - это только 50% действия :)
---
Недавно оптимизировал такой код:

```1c
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    | РеализацияТоваровУслуг.Ссылка
    |ИЗ
    | Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    | ГДЕ
    | РеализацияТоваровУслуг.Проведен
    | РеализацияТоваровУслуг.Дата МЕЖДУ ДатаС И ДатаПо";
    Запрос.УстановитьПараметр("ДатаС", ТекущаяДата()-3*86400);
    Запрос.УстановитьПараметр("ДатаПо", ТекущаяДата());
    Результат = Запрос.Выполнить();

    Выборка = Результат.Выбрать();

    ТЗ_ИНН = Новый ТаблицаЗначений;
    ТЗ_ИНН.Колонки.Добавить("ИНН");

    Пока Выборка.Следующий() Цикл
    НовСтр = ТЗ.Добавить();
    НовСтр.ИНН = Выборка.Ссылка.Организация.ИНН;
    КонецЦикла;
    ТЗ_ИНН.Свернуть("ИНН");
```

А еще жалобы были - что иногда ошибка вываливается на строке с Выборка = Результат.Выбрать();
---
это ж классика говнокода :)

А еще жалобы были - что иногда ошибка вываливается на строке с Выборка = Результат.Выбрать();

И какая там ошибка появлялась?
---
Вообще-то еще на этапе Запрос.Выполнить() должно упасть. В секции ГДЕ отсутствует соединитель условия "И".
---
Доброго утра.

Я хочу продолжить эту тему
у меня возник такой вопрос.
Я соединяю ТЗ с новым запросом.

```1c
    ТЗ = Объект.ТЗ.Выгрузить();
    ....................................................

    |ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.КУ_Взаиморасчеты.ОстаткиИОбороты(, &КонецПериода, , , ) КАК КУ_ВзаиморасчетыОстатки
    ....................................................
    |ГДЕ
    |
    | КУ_ВзаиморасчетыОстатки.ПериодВзаиморасчетов >= НАЧАЛОПЕРИОДА(ТаблицаДолг.НачалоПериода, ДЕНЬ)

    ....................................................
```

Как указать НачалоПериода в этом условии так
ТЗ.НачалоПериода т.е. данные из строки ТЗ?

На данном этапе указано так

```1c
    //Если Объект.ТЗ.Количество()<>0 Тогда
    // Для каждого Стр Из Объект.ТЗЦикл
    // Запрос.УстановитьПараметр("НачалоПериода", Стр.НачалоПериода);
    //КонецЦикла; //Для каждого Стр Из ТЗЦикл
    //КонецЕсли; //Объект.ТЗ.Количество()<>0 Тогда
    //
```
---
все зависит от того, какие данные нужны для выборки.
Обычно для такого случая проще соединять с таблицей движения, чем использовать виртуальную таблицу (ОстаткиИОбороты).
Если нужны обороты, то можно так:

```1c
    Запрос = Новый Запрос;
    Запрос.Текст = "
    |ВЫБРАТЬ
    | ТЗ.НачалоПериода КАК НачалоПериода,
    | ТЗ.Контрагент КАК Контрагент
    |ПОМЕСТИТЬ ВТ_ТЗ
    |ИЗ
    | &ТЗ КАК ТЗ
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | ВТ_ТЗ.Контрагент КАК Контрагент,
    | СУММА(ВЫБОР
    | КОГДА Взаиморасчеты.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
    | ТОГДА Взаиморасчеты.Сумма
    | ИНАЧЕ -Взаиморасчеты.Сумма
    | КОНЕЦ) КАК Сумма
    |ИЗ
    | ВТ_ТЗ КАК ВТ_ТЗ
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.КУ_Взаиморасчеты КАК Взаиморасчеты
    | ПО (Взаиморасчеты.Контрагент = ВТ_ТЗ.Контрагент)
    | И (Взаиморасчеты.Период >= ВТ_ТЗ.НачалоПериода)
    | И (Взаиморасчеты.Период < &КонецПериода)
    |
    |СГРУППИРОВАТЬ ПО
    | Взаиморасчеты.Контрагент
    |";

    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
    Запрос.УстановитьПараметр("ТЗ", Объект.ТЗ.Выгрузить());
```

Соответственно еще указать соединение по другим полям...
---
spacecraft , благодарю Вас за предложенное решение.

То, как Вы делаете- я делала немного по иному, например так я не делала.
 Отличные Вы приводите примеры, подробные и с описанием.

```1c
    Запрос.УстановитьПараметр("ТЗ", Объект.ТЗ.Выгрузить());
```
---
Доброго вечера.
Подскажите пожалуйста, оптимален ли такой код.
1. Из ТЧ на форме я выгрузила некоторые колонки в ТЗСуммыПрописью , затем изменила из значения и добавила новые колонки.
2. При печати идёт обращение в цикле к этой функции.

```1c
    Функция ОбластьНиз(ИмяМакета,КодЛС) //Суммы прописью
    ПарПредмета = "рубль,рубля,рублей,м,копейка,копейки,копеек,ж,2";
    ФормСтрока = "Л = ru_RU; ДП = Истина";

    //19.07.2020
    Обработка = РеквизитФормыВЗначение("Объект");
    Макет = Обработка.ПолучитьМакет(ИмяМакета);
    ОбластьНиз = Макет.ПолучитьОбласть("Низ");

    Если ТЗ.Количество()<> 0 Тогда

    ТЗСуммыПрописью = СуммыПрописью ();
    Для Каждого Строка ИЗ ТЗСуммыПрописью Цикл
    Если Строка.КодЛС = КодЛС Тогда
    ОбластьНиз.Параметры.Заполнить(Строка);
    КонецЕсли; // Строка.КодЛС = КодЛС Тогда
    КонецЦикла; //Для Каждого Строка ИЗ ТЗ Цикл

    КонецЕсли; // ТЗ.Количество()<> 0 Тогда

    Возврат ОбластьНиз;
    КонецФункции //СуммыПрописью(ИмяМакета,СуммаДолгаПр,СуммаПениПр,ГоспошлинаПР,СуммаВсегоПр) //Суммы прописью

    //Вызов функции
    Процедура Печать()
    Пока Выборка.Следующий() Цикл
    ОбластьСуммаДолгаПрописью =
    ОбластьСуммаДолга(ИмяМакета, Выборка.КодЛС);

    КонецЦикла;
    КонецПроцедуры
```
---
Вспомнила про такое решение

```1c
    Если ТЗ.Количество()<> 0 Тогда
    ТЗСуммыПрописью = СуммыПрописью ();

    //Идём по строкам ТЗСуммыПрописью
    Для Каждого СтрокаТЗ Из ТЗСуммыПрописью Цикл
    СтрокаТЗ.КодЛС = КодЛС;
    //Делаю отбор в ТЗ и иду только по текущему ЛС
    //https://helpme1c.ru/tablica-znachenij-v-yazyke-1s-8-v-primerax
    ОтборСумм = Новый Структура;
    ОтборСумм.Вставить("КодЛС", КодЛС);
    СтрокиСумм = ТЗСуммыПрописью.НайтиСтроки(ОтборСумм);
    Для Каждого Строка Из СтрокиСумм Цикл
    ОбластьНиз.Параметры.Заполнить(Строка);
    КонецЦикла; //Для Каждого Строка ИЗ ТЗ Цикл
    КонецЦикла; //Для Каждого Строка ИЗ ТЗ Цикл
    КонецЕсли; // ТЗ.Количество()<> 0 Тогда
```