Posted in 1С: Предприятие 8.х Программирование

странные запросы 1Сv8

Открываю сегодня я код и как-то мозги мои начинает подклинивать:


ВЫБРАТЬ
    регСобытияОбъектов.Документ_Основание,
    регСобытияОбъектов.ВидДокумента,
    регСобытияОбъектов.ДатаЗаписи,
    регСобытияОбъектов.ЗаказДата,
    регСобытияОбъектов.ЗаказНомер,
    регСобытияОбъектов.Контрагент,
    регСобытияОбъектов.Организация,
    ВЫРАЗИТЬ(регСобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).Документ1С КАК ДокументЗаказа,
    ВЫРАЗИТЬ(регСобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).ДатаПоставки КАК ДатаПоставки,
    ВЫРАЗИТЬ(регСобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).ТочкаДоставки КАК ТочкаДоставки,
    ВЫБОР
        КОГДА регСобытияОбъектов.Статус ЕСТЬ NULL
            ТОГДА ЛОЖЬ
        ИНАЧЕ ИСТИНА
    КОНЕЦ КАК Статус_ORDER,
    регСобытияОбъектов.ТекстОшибки
ПОМЕСТИТЬ основнаяORDER
ИЗ
    РегистрСведений.СобытияОбъектов КАК регСобытияОбъектов
ГДЕ
    регСобытияОбъектов.ВидДокумента = ЗНАЧЕНИЕ(Перечисление.ВидыДокументов.ORDER_Входящий)
    И регСобытияОбъектов.ЗаказДата МЕЖДУ &ДатаНач И &ДатаКон
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    регСобытияОбъектов.ВидДокумента,
    регСобытияОбъектов.Статус,
    регСобытияОбъектов.ЗаказДата,
    регСобытияОбъектов.ЗаказНомер,
    регСобытияОбъектов.ТекстОшибки
ПОМЕСТИТЬ ОбъектыСобытияСтатус
ИЗ
    (ВЫБРАТЬ
        МАКСИМУМ(регСобытияОбъектов.ДатаЗаписи) КАК ДатаЗаписи,
        регСобытияОбъектов.ЗаказДата КАК ЗаказДата,
        регСобытияОбъектов.ЗаказНомер КАК ЗаказНомер
    ИЗ
        основнаяORDER КАК основнаяORDER
            ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СобытияОбъектов КАК регСобытияОбъектов
            ПО основнаяORDER.ЗаказДата = регСобытияОбъектов.ЗаказДата
                И основнаяORDER.ЗаказНомер = регСобытияОбъектов.ЗаказНомер
   
    СГРУППИРОВАТЬ ПО
        регСобытияОбъектов.ЗаказДата,
        регСобытияОбъектов.ЗаказНомер) КАК ОбъектыСобытия_Последние
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.регСобытияОбъектов КАК регСобытияОбъектов
        ПО ОбъектыСобытия_Последние.ДатаЗаписи = регСобытияОбъектов.ДатаЗаписи
            И ОбъектыСобытия_Последние.ЗаказДата = регСобытияОбъектов.ЗаказДата
            И ОбъектыСобытия_Последние.ЗаказНомер = регСобытияОбъектов.ЗаказНомер

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


ВЫБРАТЬ
    СобытияОбъектов.Документ_Основание,
    СобытияОбъектов.ВидДокумента,
    СобытияОбъектов.ДатаЗаписи,
    СобытияОбъектов.ЗаказДата,
    СобытияОбъектов.ЗаказНомер,
    СобытияОбъектов.Контрагент,
    СобытияОбъектов.Организация,
    ВЫРАЗИТЬ(СобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).Документ1С КАК ДокументЗаказа,
    ВЫРАЗИТЬ(СобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).ДатаПоставки КАК ДатаПоставки,
    ВЫРАЗИТЬ(СобытияОбъектов.Документ_Основание КАК Документ.ЭКОМ_Документы).ТочкаДоставки КАК ТочкаДоставки,
    ВЫБОР
        КОГДА СобытияОбъектов.Статус ЕСТЬ NULL
            ТОГДА ЛОЖЬ
        ИНАЧЕ ИСТИНА
    КОНЕЦ КАК Статус_ORDER,
    СобытияОбъектов.ТекстОшибки
ПОМЕСТИТЬ основнаяORDER
ИЗ
    РегистрСведений.СобытияОбъектов КАК СобытияОбъектов
ГДЕ
    СобытияОбъектов.ВидДокумента = ЗНАЧЕНИЕ(Перечисление.ВидыДокументов.ORDER_Входящий)
    И СобытияОбъектов.ЗаказДата МЕЖДУ &ДатаНач И &ДатаКон
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
    СобытияОбъектов.ВидДокумента,
    МАКСИМУМ(СобытияОбъектов.ДатаЗаписи) КАК ДатаЗаписи,
    СобытияОбъектов.Статус,
    СобытияОбъектов.ЗаказДата,
    СобытияОбъектов.ЗаказНомер,
    СобытияОбъектов.ТекстОшибки
//ПОМЕСТИТЬ ОбъектыСобытияСтатус
ИЗ
    основнаяORDER КАК основнаяORDER
   
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СобытияОбъектов КАК СобытияОбъектов
    ПО основнаяORDER.ЗаказДата = СобытияОбъектов.ЗаказДата
     И основнаяORDER.ЗаказНомер = СобытияОбъектов.ЗаказНомер
     И основнаяORDER.ВидДокумента = ЗНАЧЕНИЕ(Перечисление.ВидыДокументов.ORDER_Входящий)

СГРУППИРОВАТЬ ПО
    СобытияОбъектов.ВидДокумента,
    СобытияОбъектов.Статус,
    СобытияОбъектов.ЗаказДата,
    СобытияОбъектов.ЗаказНомер,
    СобытияОбъектов.ТекстОшибки

Обратите внимание, здесь нужно лишь ЛЕВОЕ СОЕДИНЕНИЕ без вложенных подзапросов. Фактически я отбираю еще раз по той же таблице последние даты а затем к ним присоединяю необходимые последние значения. Последними они становятся т.к. я группирую поля и делаю функцию МАКСИМУМ() во 2м запросе.

Это изменение ускорило запрос на 20%

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.СобытияОбъектов КАК СобытияОбъектов
ПО основнаяORDER.ЗаказДата = СобытияОбъектов.ЗаказДата
И основнаяORDER.ЗаказНомер = СобытияОбъектов.ЗаказНомер
И основнаяORDER.ВидДокумента = ЗНАЧЕНИЕ(Перечисление.ВидыДокументов.ORDER_Входящий)

Обратите внимание что обращение к составным реквизитам нужно делать через ВЫРАЗИТЬ() явно указывая какого типа этот реквизит.

ВЫРАЗИТЬ(регСобытияОбъектов.ДокументОснование КАК Документ.ЭКОМДокументы).Документ1С

Как Вы видите здесь есть Неявное соединение с таблицей в которой хранится Документ_Основание. Поскольку от туда же берутся и остальные реквизиты то оптимизировать скорость этого запроса не удастся явно указывая соединение. Это и стало причиной, что я оставил данный код без изменений.

Posted in 1С: Предприятие 8.х

ДанныеФормыДерево ЗначениеВДанныеФормы недопустимое значение параметра (параметр номер ‘2’) УФ

Разрабатывая в режиме совместимости интерфейса 1C 8.2 столкнулся с тем, что на УФ ЗначениеВРеквизитФормы() выдает ошибку когда пытаешься загрузить пустое ДеревоЗначений в РеквизитФормы типа ДанныеФормыДерево

Решением считаю выгружать только те колонки дерева значений в элемент формы которые есть в этом элементе.

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

Ниже код для добавления в свои фреймворки.


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

Процедура СкопироватьСовпадающиеКолонкиВРезультат(Источник, Приемник) Экспорт
    Если НЕ (ТипЗнч(Источник) = Тип("ДеревоЗначений") И ТипЗнч(Приемник) = Тип("ДеревоЗначений")) Тогда
        Возврат;
    КонецЕсли;
   
    Источник = Новый ДеревоЗначений;
   
    ВсеКолонкиИсточника = Источник.Колонки;
    ВсеКолонкиПриемника = Приемник.Колонки;
   
    КолонкиДляКопирования = Новый Массив;
    Для каждого КолонкаИсточник Из ВсеКолонкиИсточника Цикл
        ИмяКолонки = КолонкаИсточник.Имя;
        ТипКолонки = КолонкаИсточник.ТипЗначения;
       
        ТакаяЖеКолонкаПриемник = ВсеКолонкиПриемника.Найти(ИмяКолонки);
       
        Если ТакаяЖеКолонкаПриемник <> Неопределено И ТипЗнч(ТакаяЖеКолонкаПриемник.ТипЗначения) Тогда
            КолонкиДляКопирования.Добавить(ИмяКолонки);
        КонецЕсли;
    КонецЦикла;
    Если КолонкиДляКопирования.Количество() = 0 Тогда
        Источник = Приемник.Скопировать();
        Источник.Строки.Очистить();
    Иначе
        ВыгрузитьСтрокиЭлементаДереваЗначений(Источник, Приемник, КолонкиДляКопирования);
    КонецЕсли;
КонецПроцедуры //СкопироватьСовпадающиеКолонкиВРезультат()

Функция ПопыткаЗначениеВРеквизитФормы(Источник, Приемник)
    Если ЗначениеЗаполнено(Источник) Тогда
        Попытка
            ЗначениеВРеквизитФормы(Источник, Приемник);          
        Исключение
            ПриемникРезультат = РеквизитФормыВЗначение(Приемник, Тип("ДеревоЗначений"));
            СкопироватьСовпадающиеКолонкиВРезультат(Источник, ПриемникРезультат);
            ЗначениеВРеквизитФормы(ПриемникРезультат, Приемник);
            //ОписаниеОшибки()
        КонецПопытки;
    КонецЕсли;
   
КонецФункции
Posted in 1С: Предприятие 8.х Программирование

1Cv8 Отбор в запросе ссылок <Объект не найден>

В запросе 1С можно выборочно включать поля в запрос по условию наличия или отсутствия битых ссылок:

ВЫБРАТЬ
ВЫБОР
КОГДА
Прайс.Номенклатура.Ссылка ЕСТЬ NULL
ТОГДА NULL
ИНАЧЕ Прайс.Номенклатура
КОНЕЦ КАК Номенклатура

также можно отбирать по результаты запроса по условию битой ссылки:

ГДЕ
НЕ (Прайс.Контрагент.Ссылка ЕСТЬ NULL)

Сам запрос может выглядеть примерно так:

ВЫБРАТЬ
ВЫБОР
КОГДА
Прайс.Номенклатура.Ссылка ЕСТЬ NULL
ТОГДА NULL
ИНАЧЕ Прайс.Номенклатура
КОНЕЦ КАК Номенклатура,
Прайс.Цена
ИЗ
РегистрСведений.Прайс КАК Прайс
ГДЕ
НЕ (Прайс.Контрагент.Ссылка ЕСТЬ NULL)

Posted in 1С: Предприятие 8.х Программирование

как в запросе 1Сv8 преобразовать дату в начало дня?

для преобразования даты в начало дня нужно использовать функцию запросов НАЧАЛОПЕРИОДА()


НАЧАЛОПЕРИОДА(ДокументЗаказ.Дата, ДЕНЬ)

Posted in 1С: Предприятие 8.х

Как не надо писать код в 1Сv8 и вообще в 1С

Как не надо писать код:


Если НЕ ПустаяСтрока(ТекСтрока.ЕдиницаИзмерения.ЕдиницаПоКлассификатору.МеждународноеСокращение) Тогда       
   лUNIT = СокрЛП(ТекСтрока.ЕдиницаИзмерения.ЕдиницаПоКлассификатору.МеждународноеСокращение);               
КонецЕсли;

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

Кроме того, как Вы заметили эти 2 подзапроса выполняются еще и 2 раза: один в условии и один в присвоении значения. Это рост нагрузки на сервер, БД, сеть и клиента, не 2 раза на каждую строку, а в 4 раза.

как надо:


лЕдИзмENG = ТекСтрока.ЕдиницаИзмерения.ЕдиницаПоКлассификатору.МеждународноеСокращение;
Если НЕ ПустаяСтрока(лЕдИзмENG) Тогда     
   лUNIT = СокрЛП(лЕдИзмENG);             
КонецЕсли;

Posted in 1С: Предприятие 8.х Программирование

как сформировать строку подключения к ODBC через мастер ODBC подключений

Для работы с мастером нужно использовать COM-объект DataLinks. Вот код для этого:


    Соединение = Новый COMОбъект("ADODB.Connection");
    ДатаЛ = Новый COMОбъект("DataLinks");
    Соединение.ConnectionString = Строка_Подключения;
    ДатаЛ.PromptEdit(Соединение);
    Строка_Подключения = Соединение.ConnectionString;

где Строка_Подключения это реквизит или переменная куда сохраняем строку подключения и откуда читаем строку подключения.

передача Соединение.ConnectionString строки подключения позволяет вставить все настройки строки подключения в мастер и не вводить их повторно.

Posted in 1С: Предприятие 8.х

Конкатенация (сложение) строк в запросе 1С v8


ВЫБРАТЬ
ВЫРАЗИТЬ(
  ВЫРАЗИТЬ("123" КАК Строка(15))
+
  ВЫРАЗИТЬ("789" КАК Строка(15))
КАК Строка(15)
) КАК Результат
ИЗ
Справочник.Номенклатура КАК Номенклатура

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

Posted in 1С: Предприятие 8.х Программирование

Как в 1Cv8 (1С: Предприятие версий 8.x) быстро создать XDTO объект, если есть шаблон результирующего XML файла?

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


стрКодировка = "Windows-1251";
ШаблонОтветаXML   = ЭтотОбъект.ПолучитьМакет("ШаблонОтветаXML");
локИмяВременногоФайла = ПолучитьИмяВременногоФайла("xml");
ШаблонОтветаXML.Записать(локИмяВременногоФайла);

локЧтениеXML = Новый ЧтениеXML;
локЧтениеXML.ОткрытьФайл(локИмяВременногоФайла);
   
локФабрикаXDTO = Новый ФабрикаXDTO;
ОбXDTO = локФабрикаXDTO.ПрочитатьXML(локЧтениеXML);

шаблон можно сохранить в макетах обработки (или конфигурации) и читать через команды:


ШаблонОтветаXML   = ЭтотОбъект.ПолучитьМакет("ШаблонОтветаXML");
локИмяФайлаОтвета = ПолучитьИмяВременногоФайла("xml");
ШаблонОтветаXML.Записать(локИмяФайлаОтвета);
Posted in 1С: Предприятие 8.х Программирование

Как в 1Сv8 (1С: Предприятие версий 8.x) указать параметры XML файла, включая кодировку?


локЗаписьXML = Новый ЗаписьXML();
локЗаписьXML.ОткрытьФайл(ПолучитьИмяВременногоФайла(".xml"), "windows-1251");
//именно эта строка записывает
//&lt;?xml version="1.0" encoding="windows-1251"?>
локЗаписьXML.ЗаписатьОбъявлениеXML();

кодировка указывается строкой


локЗаписьXML.ОткрытьФайл(ПолучитьИмяВременногоФайла(".xml"), "windows-1251");

объявление параметров XML файла записывается строкой


локЗаписьXML.ЗаписатьОбъявлениеXML();
Posted in 1С: Предприятие 8.х Программирование

как в 1Сv8 (1С: Предприятие версий 8.x) быстро записать объект XDTO фабрикиXDTO в файл XML?

чтобы записать объект нужно создать объект ЗаписьXML, открыть файл в который будешь писать и вызвать у фабрики XDTO метод ЗаписатьXML() с параметрами (указываю по порядку):

  • Объект ЗаписьXML который будет осуществлять запись
  • ОбъектXDTO который будет записан в файл
  • ИмяВетки-контейнера (обрамляющий тег)

локЧтениеXML.ОткрытьФайл(стрИмяФайла);
ОбXDTO = локФабрикаXDTO.ПрочитатьXML(локЧтениеXML);
//имея некоторый объект полученный от ФабрикиXDTO, например, как я указал выше, нужно сделать так:
локЗаписьXML = Новый ЗаписьXML();
локЗаписьXML.ОткрытьФайл(ПолучитьИмяВременногоФайла(".xml"), "windows-1251");
локЗаписьXML.ЗаписатьОбъявлениеXML();
локФабрикаXDTO.ЗаписатьXML(локЗаписьXML, ОбXDTO,"Файл");
Posted in 1С: Предприятие 8.х Программирование

1C8 важно, чтобы XSD схема была в кодировке UTF-8

я загружал XSD схему в кодировке windows-1251 в CериализаторXDTO

1С8 выдавала ошибку 

Ошибка при вызове метода контекста (СоздатьФабрикуXDTO)
локФабрикаИзXSD = СоздатьФабрикуXDTO(локИмяФайлаXSD_Ответа);
по причине:
Ошибка разбора XML: — [2,21] Фатальная ошибка:
Input is not proper UTF-8, indicate encoding !
Bytes: 0xD4 0xE0 0xE9 0xEB

Сохранил XSD файл в кодировке UTF-8  и все заработало.

также эту проблему можно устранить указав в начале XSD файла тег


&lt;?xml version="1.0" encoding="windows-1251"?>