Особенности языка запросов 1С.




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2025-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

94 Comments

  1. ChiginAV

    Опечатка

    «ВЫБРАТЬ Справочник.Банки.*» Выбирает все поля из справочника Товары

    Reply
  2. Ekovichev

    Спасибо. Исправил

    Reply
  3. ADirks

    Насчет подзапросов и временных таблиц я бы поосторожнее раздавал такие рекомендации.

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

    Во вторых, надо уточнить, о каких СУБД речь, потому что для MS SQL это абсолютно неверное утверждение. В лучшем случае, мы получим то же время выполнения. А в худшем — заметно больше, и попутно нагрузим сервер.

    И ещё, не надо пытаться быть умнее оптимизатора — у него гораздо больше информации для принятия решения.

    Reply
  4. KAPACEB.AA

    Спасибо за статью!

    В п. 7 я бы все-таки уточнил, что левое соединение становится внутренним как следствие особенностей отработки условий ГДЕ, в которых одно из сравниваемых равно NULL — в таком случае условие возвращает NULL, что равносильно ЛОЖЬ. Имхо, в данном случае правильнее писать что-нибудь вроде «… ГДЕ ЕСТЬNULL(Оплата.Организация, Неопределено) = &Организация.

    Reply
  5. Ekovichev

    Возможно вы правы,еще потестирую соединения с «тяжелыми» вложенными запросами на MySQL, посмотрим на разницу. Дело в том, что это не только мои рекомендации, так рекомендуют делать в метод. литературе 1С. И в типовых решениях я ни разу не видел соединений с вложенными запросами, хотя может и плохо смотрел. Спасибо за замечание, потестим получше

    Reply
  6. sommid

    по пункту 7 можно делать и так:

    ВЫБРАТЬ
    Клиенты.Ссылка КАК Клиент,
    Оплата.Ссылка КАК Оплата
    ИЗ
    Справочник.Клиенты КАК Клиенты
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Оплата КАК Оплата
    ПО Клиенты.Ссылка = Оплата.Клиент
    И Оплата.Организация = &Организация
    Reply
  7. dagder

    Посмотрите ЗУП. Несколько уровней вложенности запросов с соединениями.

    Reply
  8. Ekovichev

    (6) sommid, Пункт 7, про конструкцию «ГДЕ», у вас нет конструкции «ГДЕ» в запросе:)

    Reply
  9. Yashazz

    Это такая акция, что ли? Перепости общеизвестную чужую книжку на ИС и получи много плюсов и стартманей?

    Reply
  10. sommid

    (8) ну да, может под имя раздела и не попал ). но отработает аналогично поставленной задаче

    Reply
  11. Трофимов_Николай

    Автору:Попробуйте перед размещением текста статьи проверять ее в WORD.Статья изобилует грамматическими ошибками:»комопновки»,»уопрядочивание» и т.д.

    Reply
  12. Ekovichev

    (11) nicol, Справедливое замечание, писал на ноуте, пальцы большие, кнопки маленькие:), но это не оправдывает, замечание учел, ошибки поправил.

    Reply
  13. p1l1gr1m

    Пункт 7 срочно исправьте.

    «так как условие «ГДЕ» наложенное на правую таблицу, неявно превратило левое соединение во внутреннее» — это неправильное обоснование, новичков может ввести в заблуждение. В запросе из примера п. 7, в случае когда не произошло левого соединение таблицы Клиенты с таблицей Оплата, в конструкции ГДЕ производится сравнение null (это значение принимает в выборке поле Оплата.Организация, когда не произошло левое соединение с таблицей Клиенты) со значением из параметра «Организация», а булева операция проверки любого значения на равенство с null всегда вернет null, что в случае отбора по выборке интерпретируется СУБД как Ложь и соответственно поэтому не возвращаются строки выборки, где для строк из таблицы Оплата нет соотв. строк из таблицы Клиенты.

    Поэтому лучше в п. 7 объяснить что такое троичная логика с null и каковы особенности ее реализации в современных СУБД.

    Reply
  14. sa1m0nn

    Спасибо за статью.

    ЗЫ: Освежите правила русского и поправьте в статье лишние мягкие знаки повально. «Все запросы, которые содержатЬся в статье»

    Спасибо.

    Reply
  15. Serj1C

    (3), (5) соединения с под запросами не оптимальны всегда.

    Об этом пишут на http://kb.1c.ru/articleView.jsp?id=44

    Говорят на тренинге 1С:Эксперт, спрашивают на экзамене.

    По подзапросу нет статистики, а когда нет данных о таблице SQL выбирает способ соединения который ему проще всего — nested loops. В этом и проблема.

    Reply
  16. Ekovichev

    (13) p1l1gr1m, перефразировал в пункте 7 обоснование. Но ваше замечание:

    «в конструкции ГДЕ производится сравнение null (это значение принимает в выборке поле Оплата.Организация, когда не произошло левое соединение с таблицей Клиенты)» Почему оно принимает значение NULL?Это справедливо, если не было вообще документа оплата для клиента. Например мы знаем, что оплаты для всех клиентов точно есть, но по разным организациям. Т.е. в таблице будут все клиенты и все оплаты, но когда на полученную таблицу наложится условие «ГДЕ», то в этом случае не будет сравнения Null с Null.

    Reply
  17. ADirks

    (15) В 1С вам ещё не то напишут, надо же иногда планы запросов самостоятельно курить.

    И вообще, как можно верить людям, которые бацают кластерный индекс по GUID?!!

    Reply
  18. ShantinTD

    далее…

    Reply
  19. ShantinTD
    Reply
  20. Ekovichev

    У меня нет такой здоровой таблицы под рукой, попробуйте так:

    ВЫБРАТЬ

    ЦеныНоменклатурыМагазинов.Номенклатура,

    ПРЕДСТАВЛЕНИЕ(ЦеныНоменклатурыМагазинов.Номенклатура) КАК ПредставлениеНоменклатуры

    ИЗ

    РегистрСведений.ЦеныНоменклатурыМагазинов КАК ЦеныНоменклатурыМагазинов

    Reply
  21. ShantinTD

    (20) как и предположил глядя на предложенный запрос — время выполнения только увеличилось. До ~60 секунд. Объем выборки не изменился.

    Тут читаем Встроенные функции языка запросов

    Функция ПРЕДСТАВЛЕНИЕ

    Описание:

    Данная функция предназначена для получения строкового представления значения произвольного типа.

    Параметр функции – выражение любого типа.

    Возвращаемое значение – представление значения, тип Строка.

    Результат работы функции не может быть использован внутри других функций, за исключением функции ПРЕДСТАВЛЕНИЕ.

    Так что пользы пока что вижу например в этом:

    ВЫБРАТЬ
    ПРЕДСТАВЛЕНИЕ(5)
    

    , т.к.

    ВЫБРАТЬ
    ВЫРАЗИТЬ(5 КАК СТРОКА(1))

    вызовет ошибку.

    У меня нет такой здоровой таблицы под рукой

    . У меня 1000000 записей в тестовой базе (устаревшей). В живой базе — еще круче.

    Reply
  22. Dzenn

    Ставлю плюс, но тема сисек запросов раскрыта не полностью. Где описание конструкции «ИМЕЮЩИЕ»?

    Reply
  23. Ekovichev

    (21) ShantinTD, Завтра проверю, справочники есть, там миллионы записей, просто проверял на выборках в несколько тысяч, разницы во времени не заметил. Интересное наблюдение

    Reply
  24. KAPACEB.AA

    (13) p1l1gr1m,

    Поддерживаю! Собственно, об этом я и пытался сказать в своем комменте 🙂

    Reply
  25. Ekovichev

    (22) DZENN, Добавил в статью, 11 пункт.

    Reply
  26. ADirks

    (19)

    А вот ПРЕДСТАВЛЕНИЕ() у меня (1С 8.3.4.304 и PostgreSQL 9.1.2-1.1С) дало неожиданно печальный результат: время выполнения запроса с 1`007`071 записью (выборка ссылок на элементы справочника из регистра сведений) выросло в 5 (задумайтесь только!) раз, против выборки непосредственно ссылок (49 секунд с представлениями против 9 секунд со ссылками).

    Интересное кино… А можно ли как-то посмотреть, какой финальный запрос уходит на сервер? Неужто простой join с таблицей номенклатуры даёт такой эффект?

    Reply
  27. ADirks

    (+26) ну и это, сравнивать то надо эквивалентные вещи, т.е. не

    ВЫБРАТЬ

    ЦеныНоменклатурыМагазинов.Номенклатура

    ПОМЕСТИТЬ

    ВТ

    ИЗ

    РегистрСведений.ЦеныНоменклатурыМагазинов КАК ЦеныНоменклатурыМагазинов

    а

    ВЫБРАТЬ

    ЦеныНоменклатурыМагазинов.Номенклатура

    ИЗ

    РегистрСведений.ЦеныНоменклатурыМагазинов КАК ЦеныНоменклатурыМагазинов

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

    Reply
  28. Ekovichev

    (24) Mu_meson, Добавил пункт 12 в статью, немного про NULL, постарался объяснить как мог.

    Reply
  29. ADirks

    Эксперимент на MS SQL

    select

    рег.Номенклатура

    into #t1

    from

    регПартииНаличие рег

    select

    Н.Наименование

    into #t2

    from

    регПартииНаличие рег

    left join спрНоменклатура Н ON Н.ID = рег.Номенклатура

    показал раскладку 31% / 69 % , т.е. время увеличилось примерно в 2 раза, что вполне ожидаемо

    Reply
  30. Gilev.Vyacheslav

    (3) ADirks, Алексей, вы большой специалист по запросам? )))

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

    Минусы:

    для создания временной таблицы требуется время;

    для каждого соединения свои изолированные таблицы;

    временные таблицы при заполнении большим объемом данных тратят много времени;

    создание индексов для временных таблиц это еще дополнительное время;

    осторожнее с ораклом, включая 11 версию субд плохо дело со статистикой;

    слишком большое количество временных таблиц может занять много места на диске.

    Плюсы:

    в отличии от вложенных запрос количество строк во временной таблице ПРОГНОЗИРУЕМОЕ, именно «ясность» с объемом выборки делает их удобными для оптимизации мест, которые выполняются неоправдано долго;

    временные таблицы не пересекаются по блокировкам;

    временные таблицы могут позволить не совершать повторные действия над одними и теме же данным в сложном запросе;

    временные таблицы можно использовать для сбора промежуточных результатов из «подзапросов», таким образом это может упростить контроль RLS (т.е. проверке подвергать только итоговые данные, а не все промежуточные действия в сложном запросе).

    Reply
  31. ADirks

    (30)

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

    Да, но методичка то от 1С как раз таки советует бездумно его применять.

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

    Reply
  32. yuraos

    Мддда!

    Оччередной лииииикбез …. и восторги начинающих.



    Хотел минусануть — да раздумал.

    Reply
  33. yuraos

    (32)



    Для демонстрации своей конструктивности предлагаю автору

    (и думаю что коллеги знакомые с более развитыми SQL-языками меня поддержат)

    указать следующие особенности языка запросов 1С:

    Reply
  34. yuraos

    (33)

    1) Функциональная ограниченность:

    Очень небольшой список встроенных функций.

    Хотя бы взять категорию строковых функций:

    — нет функций отсекающие в строках пробелы (TRIM и ее разновидности);

    — нет функции, возвращающей число символов в строке;

    — нет функций, пребразующих число к его какому-нибудь строковому представлению

    (а складывать строки с числами — нельзя!!!);

    Reply
  35. Ekovichev

    Хорошо, будет время опишу ограниченности языка запросов.

    Но кстати число в строку можно превратить конструкцией ПРЕДСТАВЛЕНИЕ(«Число»). Только конкатенация в запросе с таким полем невозможна.

    Reply
  36. yuraos

    (33)

    2) Отсутствие поддержки коррелированных подзапросов:

    В 1С в запросе нельзя использовать подзапросы, зависящие от значений полей основного запроса.

    Но это было бы очень полезно в ситуациях, подобных следующей:

    Требуется вывести продажи в разрезе по строкам документов продаж

    и независимо цену продаж из регистров цен,

    но не на дату отчета — а на дату документа продажи.


    Нужный подзапрос цен может кроме номенклатуры и даты цены зависить еще и от типа цен и т.п.



    Впринципе это ограничение обходится



    НО ЦЕНОЙ АБСОЛЮТНОЙ ПОТЕРИ ЧИТАЕМОСТИ ТЕКСТА ЗАПРОСА!!!

    Reply
  37. yuraos

    (33)

    3) Ну а про возможность использования запросов для модификации данных

    (хотя во временных таблицах) — можно даже и не мечтать!!!

    Reply
  38. zarucheisky

    //Добавлю немножко полезный (иногда) пример:

    SELECT 1 A ,2 B INTO A UNION ALL

    SELECT 3 A ,4 B UNION ALL

    SELECT 5 A ,6 B UNION ALL

    SELECT 7 A ,8 B;

    SELECT 1 A ,2 B INTO B UNION ALL

    //SELECT 2 A ,4 B UNION ALL

    //SELECT 5 A ,6 B UNION ALL

    SELECT 7 A ,8 B;

    SELECT t_A.A,t_A.B FROM A t_A WHERE (t_A.A,t_A.B) NOT IN (SELECT t_B.A,t_B.B FROM B t_B)

    // Здесь, что и интересно в условии фигурирует кортеж (t_A.A,t_A.B) и условие исключения из множества

    // SELECT t_B.A,t_B.B FROM B t_B

    Reply
  39. SatanClaws

    (33) yuraos,

    А экзист-то прикрутили, или воз и ныне там?

    Reply
  40. yuraos

    (39) SatanClaws,

    и ныне там …

    … специально ради проверки качнул платформу 8.3



    как видно на скриншоте, из ключевых слов

    ALL ANY SOME EXISTS IN TOP

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

    ALL IN и TOP (ALL — используется по другому поводу — в объединениях запросов)

    Reply
  41. yuraos

    (40)

    впрочем это естественно.

    раз нет коррелированных подзапросов —

    — значит и нет смысла в использовании оператора EXISTS .



    еще можно добавить что язык запросов 1С (как и встроенный)

    не поддерживают блочных комментариев.

    Reply
  42. yuraos

    Блин!!!

    Что-то Инфостарт после «линьки» глючит не по детски:

    1. Подписка на комментарии не идет на почту (только спам от спекулянтов старт-манями).

    2. Жму на «Просмотр» вводимого поста, а пост по простецки добавляется при этом на ветку.

    Reply
  43. echo77

    (9) Да! Вот мой пример: http://infostart.ru/public/118422/

    Плюсов больше чем за все остальные мои публикации вместе взятые 🙂

    Reply
  44. Ekovichev

    (42) yuraos, Тоже самое, упарило уже

    Reply
  45. echo77

    (0)

    2. Упорядочивание данных по ссылочному полю

    Не советую приучать новичков использовать АВТОУПОРЯДОЧИВАНИЕ, т.к. оно требует дополнительного обращения к метаданным, тем самым увеличивает время выполнения запроса.

    Виртуальные таблицы , позволяют получить практически готовые данные для большинства прикладных задач.(СрезПервых,СрезПоследних,Остатки,Обороты,ОстаткиИОбороты) Ключевое слово здесь виртуальные. Эти таблицы не являются физическими, а компонуются системой налету, т.е. при получении данных из виртуальных таблиц система собирает данные из итоговых таблиц регистров, компонует, группирует и выдает пользователю.

    Для регистров накопления и бухгалтерии виртуальные таблицы — это физические таблицы в БД.

    На платформе 8.0-8.2 виртуальные таблицы периодических регистров сведений — это хранимые процедуры, т.е. действиетельно вирутальные таблицы. Нововведением на платформе 8.3 стало то что у периодических регистров сведений теперь будет еще и физическая таблица, которая хранит самые ранние записи(СрезПервых) и самые последние(СрезПоследних)

    Поправьте меня, если где-то соврал

    Reply
  46. Ekovichev

    (45) echo77, Подкорректировал пункт про автоупорядочивание, тут вы правы. Про 8.3 и вирт. таблицы покурю еще:) Спасибо за констр. замечания

    Reply
  47. gaglo

    (45) и (46) — подозреваю, что подкорректировали и перегнули в другую сторону. ИМХО — АВТОУПОРЯДОЧИВАНИЕ способно серьезно замедлить запрос только в сочетании с отсутствием фразы УПОРЯДОЧИТЬ ПО. Туманное же указание на «некоторые» (неописанные) «случаи» практически ничего не дает.

    Reply
  48. nikolal

    В п.7 не учтен вариант, описанный в комментарии http://forum.infostart.ru/forum24/topic75954/message1003240/#message1003240

    Reply
  49. Ekovichev

    (48) nikolal, Интересное решение, можно сделать и так. Добавлю в статью.Спасибо.

    Reply
  50. chmv

    Очень интересно

    Reply
  51. kraynev-navi

    Спасибо. Очень доступно.

    Кое-где в запросах тег br проскочил

    ————

    ГДЕ< br > Клиенты.Ссылка В (&Клиенты)

    ————

    Reply
  52. DAnry

    Вообще то все это известно, ничего нового. Но для новичков полезно…

    Reply
  53. Dementor

    В свете пункта 12. Значение NULL не будет лишним отметить, что все поля через точку в запросе для пустых ссылок содержат значение NULL. Об этом часто забывают и считают, что платформа по аналогии с объектной моделью будет ставить значения по-умолчанию для нужных типов.

    P.S. что-то тут на инфостарте нахимичили и без авиков комментарии теперь не добавить…

    Reply
  54. anchovy

    >>Только в первом запросе записей будет меньше так, как записи , например с одинаковой номенклатурой, свернутся.

    Разные запросы дают разные результаты. Удивительно.

    Reply
  55. bulpi

    В п.12 вместо

    Справочник.КПК_Пайщики КАК КПК_Пайщики

    нужно

    Справочник.Клиенты КАК Клиенты

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

    Reply
  56. AlexeyFreeLife

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

    Reply
  57. SatanClaws

    (41)

    Не, у меня как-то без коррелированных возникло желание.

    Т.е. я на автомате, после 1ЦПП-шных прямых запросов, написал какую-то конструкцию с EXISTS — а восьмерка ее не съела.

    Покурил маны — с удивлением обнаружил что его там не вообще.

    Решить, конечно же, решил — но как-то через задницу (что-то в духе CASE WHEN (SELECT TOP 1 Поле FROM …) IS NOT NULL THEN …).

    А вот моральная травма осталась на всю жЫзнь.

    Reply
  58. VasilevaHelen

    Согласна с(52), ставлю «+».

    Reply
  59. BAPBAP

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

    Reply
  60. chmv

    59 Так наглаяднее

    Reply
  61. ShantinTD
    Reply
  62. mr.Kot

    Полезная статья, знание запросов — первое, что проверяют на собеседованиях, т.к. в запросы обычно долго «вкуривают».

    Reply
  63. el7

    запросы вещь отличная, и очень-очень полезная)))

    Reply
  64. DrAku1a

    ИМХО: Статья из разряда «Золотые страницы Инфостарта».

    Такие знания и применение их на практике — это одна из деталей, которая делает из программиста настоящего профессионала!

    Reply
  65. zarucheisky

    Сколько уже писано/переписано тем про запросы на той же мисте.

    ИМХО, при написании запросов важно понимать ЧТО, ОТКУДА и КАК выбрать надо.

    Избегать многоточий в выражениях языка запросов.

    Ну и для начала лучше всего проштудировать что-то типа Ицик Бен-Ган Основы t-SQL для общего развития.

    Reply
  66. ZLENKO

    Почитал комментарии — любят 1С-неги измерять размеры… 🙂

    Reply
  67. Rik30

    а как в запросе выбрать все справочники? Допустим нужно в запросе узнать кол-во записей всех справочников БД.

    Reply
  68. Ekovichev

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

    КОЛИЧЕСТВО(Различные(<Справочник1>.Ссылка) КАК КоличествоЗаписей

    ОБЪЕДИТЬ ВСЕ

    КОЛИЧЕСТВО(Различные(<Справочник2>.Ссылка) КАК КоличествоЗаписей

    ….

    Потом просуммировать.

    Или программно:

    Для Каждого Справочник Из Метаданные.Справочники Цикл

    Запрос=Новый Запрос;

    Запрос.Текст=

    «ВЫБРАТЬ

    | КОЛИЧЕСТВО(*) КАК Кол

    |ИЗ

    | Справочник.»+Справочник.Имя;

    КоличествоЗаписей = КоличествоЗаписей + Запрос.Выполнить().Выгрузить().Итог(«Кол»);

    КонецЦикла;

    Как-то так…

    Reply
  69. bashirov.rs

    Не плохая статейка. Спасибо!

    Reply
  70. ZloyProger

    Доброго времени суток, коллеги! Замечание по пункту 13 (короткая форма записа оператора ВЫБОР..) — кто-нибудь проверял на не примитивные (блин как-то по-русски не могу сформулировать..) условия, т.е. типа:

    ВЫБОР ЕПСБУОборотыДтКт.Регистратор ССЫЛКА
    КОГДА Документ.ОтражениеЗарплатыВУчете Тогда «Отражение ЗП»
    

    ну и т.д. Пробовал всяко и в скобках и без и такой вариант тоже

    ВЫБОР ЕПСБУОборотыДтКт.Регистратор
    КОГДА ССЫЛКА Документ.ОтражениеЗарплатыВУчете Тогда «Отражение ЗП»
    

    выдает ошибки.. Нужно для следующей задачи — «нормально» упорядочить результат запроса по виду документа и сумме.

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

    Reply
  71. soulsteps

    ZloyProger, попробуй так

    ВЫБОР ТИПЗНАЧЕНИЯ(ЕПСБУОборотыДтКт.Регистратор)

    КОГДА Документ.ОтражениеЗарплатыВУчете Тогда «Отражение ЗП»

    КОГДА Документ.<НеобходимыйТип> Тогда «НеобходимыйТип»



    КОНЕЦ

    Недавно писал отчет, использовал такую же конструкцию — все прекрасно отрабатывает.

    Reply
  72. jaroslav.h

    Ой, за «16. Вызов конструктора запросов для «условия» в пакетном запросе» это трюк я вам так благодарный )

    Reply
  73. Ekovichev

    (72) myr4ik07, Рад помочь)

    Reply
  74. markovki

    Спасибо!

    Автору 5+ за статью.

    Ставлю ПЛЮС

    Reply
  75. mtv:)

    Спасибо за статью! Углядел для себя несколько полезных фишек.

    Есть замечание:

    Совет «10. Запросы в цикле» думаю, что бесполезный.

    Ваше утверждение: «Это избавит систему от синтаксической проверки запроса в цикле.» — это миф.

    Синтаксическая проверка запроса происходит при исполнении метода Запрос.Выполнить(), а это происходит как раз в теле цикла. И из цикла это ни как не выкинешь.

    Так что от «вынесения создания запроса за пределы цикла» прироста производительности ожидать не следует.

    Reply
  76. AlexiyI

    Статья из разряда «то что надо», спасибо большое!

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

    Reply
  77. Ekovichev

    (76) AlexiyI,

    Спасибо.

    Да, вы правы по 15 пункту, внесу изменения.

    Reply
  78. dimon_upi

    Автор молодец, собрал знания в одном месте. Возможно имеет смысл написать продолжение по дзену запросов 1С и их оптимизации, если еще не написал.

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

    пункт 5 — от примера с left join и where сначала впал в недоумение, потом дочитал и понял что это из разряда — как не надо делать ) Надо до кучи еще full join пример привести. А то по началу некоторые парятся что нужно по isnull связывать в where.

    пункт 13 — вроде обычный «Case», никогда не думал что она недокументирована +)

    Для улучшения навыков в запросах 1С стоит пописать запросы на SQL, познакомится с вьюхами, триггерами, процедурами (функции ф топку). Потыкать профайлер, покурить статистику… Офигеть от того что порой план для запроса в транзакции и без отличается координально.

    Жалко что нет coalesce, exists, set statistics profile ON, хинтов, процедур и еще много-много чего из стандарта SQL :((((

    Reply
  79. kmanas

    Здравствуйте, несколько дней уже изучаю запросы, решил попрактиковаться в консоле запросов, и тут же возник вопрос, возможно ли исключить пустые строки из запроса? Код моего первого запроса прост до безобразия:

    ВЫБРАТЬ Первые 15

    Производитель

    ИЗ

    Справочник.Номенклатура

    Отобразились строки, и заполненные и пустые. Попытка писать условия добавив секцию ГДЕ не помогло. Искал в инете, но ничего толком об этом нет, косвенно есть инфа, что в самом запросе этого не сделать.

    Reply
  80. Ekovichev

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

    ВЫБРАТЬ Первые 15

    Производитель

    ИЗ

    Справочник.Номенклатура

    ГДЕ

    НЕ Производитель.Ссылка ЕСТЬ NULL

    Reply
  81. kmanas

    Да, ссылочные. Выходит в моем случае в ГДЕ к полю надо добавлять <.Ссылка>. Спасибо, работает!

    Reply
  82. 1c.pro.fun

    По поводу конструкции ПРЕДСТАВЛЕНИЕ. Если используется пакетный запрос и платформа автоматически добавляет представление при выборе поля в первом пакете, а затем это поле используется во втором и при выборе поля, платформа также добавляет представление. Явно оба представления оставлять нет смысла. Вопрос: какое из двух представлений нужно оставить? Любое? Или только в первом пакете, так как в нем происходит первоначальное обращение к данным? Как будет быстрее?

    Reply
  83. marinelle

    Добрый вечер. Имеется таблица дат, нужно присоединить квартальные обороты до даты выпуска в разрезе номенклатуры. Кто подскажет, как это сделать???

    Reply
  84. sergik_nsk

    не плохая статья чтобы освежить мозги

    Reply
  85. mgn

    ну вот влез в древнюю тему, просто хочется реабилитировать 1C в отношении exists

    все наверное забыли про

    Реализация группового оператора вхождения
    
    В отличие от простого оператора вхождения, аналог которого имеется в большинстве СУБД (оператор IN языка SQL), групповой оператор вхождения не имеет точных аналогов в SQL. Поэтому при использовании группового оператора вхождения важно учитывать механизм его перевода в SQL. Оператор вида:
    
    Копировать в буфер обмена
    (<Выражение 1>, …, <Выражение N>) В (
    ВЫБРАТЬ <Колонка 1>, …, <Колонка N>
    ИЗ <Источники>
    ГДЕ <Условие>
    )
    при выполнении его на СУБД будет иметь вид:
    
    Копировать в буфер обмена
    EXISTS(
    SELECT 1
    FROM <Источники>
    WHERE (<Условие>) AND <Выражение 1> = <Колонка 1> AND … AND <Выражение N> = <Колонка N>
    )
    Если вложенный запрос содержит агрегатные функции и/или раздел СГРУППИРОВАТЬ ПО, то групповой оператор вхождения вида:
    
    Копировать в буфер обмена
    (<Выражение 1>, …, <Выражение N>) В (
    ВЫБРАТЬ <Колонка 1>, …, <Колонка N>
    ИЗ <Источники>
    ГДЕ <Условие 1>
    СГРУППИРОВАТЬ ПО <Список группировки>
    ИМЕЮЩИЕ <Условие 2>
    )
    на языке SQL будет записан так:
    
    Копировать в буфер обмена
    EXISTS(
    SELECT 1
    FROM <Источники>
    WHERE <Условие 1>
    GROUP BY <Список группировки>
    HAVING (<Условие 2>) AND <Выражение 1> = <Колонка 1> AND … AND <Выражение N> = <Колонка N>
    )
    
    

    Показать

    Reply
  86. dimon_upi

    (85)

    exists просто привычней 😉

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

    Reply
  87. user668780_xeslifex

    Спасибо за информацию, пригодилось)

    Reply
  88. igor_gk

    Короче, в 1С уже как в механике пошло разделение на теормех и реальную работу механиков на производстве… Спасибо. Пишите побольше таких статей. Хороший уклон в простоту, понятность и практичность изложения.

    Reply
  89. marivgo

    Разве Автоупорядочивание по ссылке документа — это сортировка по сочетанию Дата и Номер, а не по моменту времени? В СКД задала в настройках сортировку строк отчета по Регистратору — предполагаю, что это аналог автоупорядочивания. Все документы выстроились действительно в порядке Дата-Номер. Но после того, как я в первом из документов вручную исправила Номер на больший (у всех остальных с той же датой были меньшие номера) , положение данного документа не изменилась. Отсюда делаю вывод, что все-таки непосредственно Номер документа в автоупорядочивании не участвует, скорее его ссылка.

    Reply
  90. borodaty_pontorez

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

    Reply
  91. Glebis

    По пункту 10. Запросы в цикле.

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

    Reply
  92. Sherkhan

    8.2 ругается на отсутствия метола «Пустой()» из п.10.

    Reply
  93. Sevt_RND

    По п.10 правильней передать всю таблицу клиентов в запрос, а не гонять цикл.

    Reply
  94. Sergey_1c

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

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *