Минимализмы 3




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2024-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='\

44 Comments

  1. Разумов

    Магия.

    Reply
  2. DarkUser

    Респект и уважуха!

    Reply
  3. headMade

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

    Например есть массив: 1,2,3,6,7,8,11,12,15.

    Надо получить интервалы 1-3,6-8,11-12,15-15.

    Спасибо.

    Reply
  4. ildarovich

    (3) В статье Минимализмы 1 задача 2.

    Reply
  5. headMade

    (4) а с использованием запроса?

    Reply
  6. ildarovich

    (5) Тогда там же, но задача 14. В задаче речь идет о датах, но будет работать и на числах

    Reply
  7. 🅵🅾️🆇
    Reply
  8. klinval

    65.

    Есть массив А из элементов некоторого справочника и есть справочник Б с табличной частью из элементов того же справочника. Найти элемент Б, где список точно совпадает с массивом А (ни больше ни меньше).

    ВЫБРАТЬ
    Менеджеры.Ссылка
    ИЗ
    Справочник.Контрагенты.МенеджерыПокупателя КАК Менеджеры
    ГДЕ
    Менеджеры.МенеджерПокупателя В(&Массив)
    СГРУППИРОВАТЬ ПО
    Менеджеры.Ссылка
    ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ Менеджеры.МенеджерПокупателя) = &МассивКоличество

    Показать

    Не работает если учитывать условие «ни больше ни меньше». Когда больше — запрос отрабатывает неверно.

    Проверяю на БП 3.0 на запросе:

    ВЫБРАТЬ
    КонтрагентыИсторияКПП.Ссылка КАК Ссылка
    ИЗ
    Справочник.Контрагенты.ИсторияКПП КАК КонтрагентыИсторияКПП
    ГДЕ
    КонтрагентыИсторияКПП.КПП В(&МассивКПП)
    
    СГРУППИРОВАТЬ ПО
    КонтрагентыИсторияКПП.Ссылка
    
    ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КонтрагентыИсторияКПП.КПП) = &МассивКППКоличество

    Показать

    Допустим возьмём контрагента у которого КПП 3 строки: 775003035, 773601001 и 631050001

    В запрос передадим массив КПП: 775003035; 773601001 и МассивКППКоличество = 2;

    Запрос возвращает результат — этого контрагента, хотя у него 3 сроки!

    Рабочий запрос:

    ВЫБРАТЬ РАЗЛИЧНЫЕ
    КонтрагентыИсторияКПП.Ссылка КАК Ссылка
    ПОМЕСТИТЬ ВсеКонтрагентыСЭтимиДанными
    ИЗ
    Справочник.Контрагенты.ИсторияКПП КАК КонтрагентыИсторияКПП
    ГДЕ
    КонтрагентыИсторияКПП.КПП В(&МассивКПП)
    
    СГРУППИРОВАТЬ ПО
    КонтрагентыИсторияКПП.Ссылка
    
    ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КонтрагентыИсторияКПП.КПП) = &МассивКППКоличество
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ РАЗЛИЧНЫЕ
    КонтрагентыИсторияКПП.Ссылка КАК Ссылка
    ИЗ
    ВсеКонтрагентыСЭтимиДанными КАК ВсеКонтрагентыСЭтимиДанными
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Контрагенты.ИсторияКПП КАК КонтрагентыИсторияКПП
    ПО ВсеКонтрагентыСЭтимиДанными.Ссылка = КонтрагентыИсторияКПП.Ссылка
    
    СГРУППИРОВАТЬ ПО
    КонтрагентыИсторияКПП.Ссылка
    
    ИМЕЮЩИЕ
    КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КонтрагентыИсторияКПП.КПП) = &МассивКППКоличество

    Показать

    Reply
  9. ildarovich

    (8) Вы правы, проблему увидел, в ближайшее время исправлю.

    Reply
  10. BackinSoda

    42 — da, eto zhestko

    Reply
  11. ildarovich

    (8) Все же решил исправить по-своему. Для старых версий платформы так:

    ВЫБРАТЬ
    КонтрагентыИсторияКПП.Ссылка КАК Ссылка
    ИЗ
    Справочник.Контрагенты.ИсторияКПП КАК КонтрагентыИсторияКПП
    СГРУППИРОВАТЬ ПО
    КонтрагентыИсторияКПП.Ссылка
    ИМЕЮЩИЕ
    СУММА(ВЫБОР
    КОГДА КонтрагентыИсторияКПП.КПП В (&МассивКПП)
    ТОГДА 1
    ИНАЧЕ 0.000001
    КОНЕЦ) = &МассивКППКоличество

    Показать

    Для новых, где логическое выражение можно записывать сразу в поле запроса, так:

    ВЫБРАТЬ
    КонтрагентыИсторияКПП.Ссылка КАК Ссылка
    ИЗ
    Справочник.Контрагенты.ИсторияКПП КАК КонтрагентыИсторияКПП
    СГРУППИРОВАТЬ ПО
    КонтрагентыИсторияКПП.Ссылка
    ИМЕЮЩИЕ
    КОЛИЧЕСТВО(*) = &МассивКППКоличество И
    МИНИМУМ(КонтрагентыИсторияКПП.КПП В (&МассивКПП)) = ИСТИНА

    Показать

    В числе строчек даже получился выигрыш.

    Спасибо за внимательность!

    Reply
  12. Дмитрий74Чел

    Оглавление

    72. Очистка строки от нецифровых символов

    71. Определение суммарного покрытия перекрывающихся интервалов

    70. Определение пересечения интервалов в кольце

    69. Быстрое удаление строк в таблице значений

    68. Получение интервалов неизменности курсов валют

    67. Определение пропусков в последовательности чисел

    66. Инвертирование периодов в запросе

    65. Проверка совпадения таблиц

    64. Проверка совпадения таблиц путем сравнения полного и внутреннего соединения

    63. Получение списка простых чисел в запросе

    62. Определение периодов работы сотрудников по данным СКУД

    61. Найти документы, во всех строках которых колонка количество меньше либо равна нулю

    60. Определение плановых остатков товара с учетом предшествующих фактических и будущих плановых продаж

    59. Сравнение плановых и фактических дней отпуска

    58. Получить дату по номеру дня недели и его порядковому номеру в месяце

    57. Получение предпоследнего курса валюты

    56. Определить элементарные интервалы, образующиеся при пересечении всех исходных интервалов

    55. Найти количество записей, повторяющихся подряд несколько дней

    54. Сравнение набора товаров, проданных сменами

    53. Найти документ, состав табличной части которого соответствует параметру — таблице значений

    52. Распределение товаров по ячейкам в запросе

    51. Объединение пересекающихся периодов в запросе

    50. Выделение разрядов числа без использования округления и деления по модулю

    49. Посчитать запросом суммарную длительность различных состояний

    48. Разбиение произвольного периода на интервалы в запросе

    47. Поиск свободного штрихкода внутри одного префикса

    46. Выбор записи по номеру из НЕПРОНУМЕРОВАННОЙ таблицы

    45. Как в запросе секунды преобразовать в часы и минуты

    44. Убрать префикс и лидирующие нули из номера

    43. Перебор всех строковых комбинаций «0» и «1» в порядке возрастания числа единиц («00000″->»00001″->»00010»-> …»01011″…)

    42. Транслитерация в запросе

    41. Заполнение пропусков в таблице цветов

    40. Количество дней недели (понедельников/вторников/…) в заданном диапазоне запросом

    39. Свернуть строки в таблице значений конкатенацией

    Reply
  13. ildarovich

    (12) Спасибо, сделаю это оглавление в самой статье.

    Reply
  14. fixxxer834

    67. следующий вариант работает на порядки быстрее для больших таблиц (если не ПЕРВЫЕ 1 — выбирает все пропущенные значения и следующее по порядку):

    ВЫБРАТЬ ПЕРВЫЕ 1

    Т1.Х + 1

    ИЗ

    Дано Т1

    ЛЕВОЕ СОЕДИНЕНИЕ

    Дано Т2

    ПО

    Т2.Х = Т1.Х + 1

    ГДЕ

    Т2.Х Есть Null

    УПОРЯДОЧИТЬ ПО

    Т1.Х

    З.Ы. на таблице в 1 млн. записей с индексированием по полю X (иначе какой смысл искать «дырки» в большой таблице и оставлять это поле неиндексированным) данный запрос выполняется за доли секунды в том случае как предложенный — десяток секунд.

    Reply
  15. ildarovich

    (14)

    иначе какой смысл искать «дырки» в большой таблице и оставлять это поле неиндексированным

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

    Reply
  16. meganibler

    может кому пригодится: нормализация представления числа

    // Приводит переданные числовые значения Мантиссы и Порядка к нормализованной форме
    // Нормализованной формой числа с плавающей запятой считается форма, когда Мантисса находится в интервале 1 ⩽ М < 10
    //
    // Параметры:
    //  ЗначениеМантисса   — Число — значение числа без учёта порядка
    //  ЗначениеПорядок    — Число — степень основания числа, на которое умножается мантисса
    //  НормализованнаяМантисса  — Число — возвращаемое нормализованное значение мантиссы
    //  НормализованныйПорядок  — Число — возвращаемое нормализованное значение порядка
    //
    Процедура НормализоватьЗначениеЧисла(ЗначениеМантисса, ЗначениеПорядок = 0, НормализованнаяМантисса = 0, НормализованныйПорядок = 0) Экспорт
    
    Если ЗначениеМантисса = 0 Тогда
    Возврат;
    КонецЕсли;
    Порядок = Log10(?(ЗначениеМантисса < 0, — ЗначениеМантисса, ЗначениеМантисса));
    Если Порядок > 0 Тогда
    Порядок = Цел(Порядок);
    Иначе
    Если Не Порядок = Цел(Порядок) Тогда
    Порядок = Цел(Порядок) — 1;
    КонецЕсли;
    КонецЕсли;
    НормализованныйПорядок = Порядок + ЗначениеПорядок;
    НормализованнаяМантисса = ЗначениеМантисса * Pow(10, ЗначениеПорядок — НормализованныйПорядок);
    
    КонецПроцедуры

    Показать

    Пример1: ЗначениеМантисса = 0,1; ЗначениеПорядок = 0; НормализованнаяМантисса = 1; НормализованныйПорядок = -1 (0,1)->(1·10#k8SjZc9Dxk-1)

    Пример2: ЗначениеМантисса = 10; ЗначениеПорядок = 6; НормализованнаяМантисса = 1; НормализованныйПорядок = 7; (10·10#k8SjZc9Dxk6)->(1·10#k8SjZc9Dxk7)

    Пример3: ЗначениеМантисса = 500; ЗначениеПорядок = 0; НормализованнаяМантисса = 5; НормализованныйПорядок = 2; (500)->(5·10#k8SjZc9Dxk2)

    Reply
  17. bolshoi

    Тоже поделюсь.

    1. Количество знаков после запятой (максимум 27).

    Точность = СтрДлина(Сред(«» + Макс(-Значение, Значение) % 1, 3));

    2. Проверка наличия заполненных значений в колонке. Пустые значения в колонке должны быть одного типа, т. е., не должны встречаться вместе, например, NULL и Неопределено.

    ЕстьЗаполненныеЗначения = (Таблица.НайтиСтроки(Новый Структура(«ИмяКолонки», ПустоеЗначение)).Количество() <> Таблица.Количество());
    Reply
  18. Marik

    По поводу «Быстрое удаление строк в таблице значений» есть сомнение в приведенном способе.

    1. Если таблица значений занимает более 100-ни Мб в ОЗУ, то получаем лишний расход ОЗУ (на 1-ю и 2-ю таблицу)

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

    Вариант синтаксиса: Скопировать по отбору

    Описание:

    Создает копию таблицы значений.

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

    Наилучшим решением будет удаление по отбору по индексированной колонке

    РабочаяТаблица.Индексы.Добавить(«КУдалению»);
    найдСтр = РабочаяТаблица.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    Для к=0 По найдСтр.ВГраница() Цикл
    РабочаяТаблица.Удалить(найдСтр[к]);
    КонецЦикла;
    Reply
  19. ildarovich

    (18) Сомневаться нужно, но, чтобы сделать выводы, нужны замеры. «Лишнего» расхода ОЗУ, нагрузки на процессор (видимо, имеется ввиду работа со структурой для работы сборщика мусора). Просто сказать «наилучшим решением будет» в данном случае недостаточно. Выигрыш приема из (69) был настолько большим (в моих измерениях), что его указанные минусы не перекрывают. — Попробуйте сделать замеры сами!

    Reply
  20. Marik

    Пожалуйста вот замеры, обратите на 2-ю строку, отбрасывая все лишнее, только процесс удаления и создания:

    1. Удаление не вашим способом

    2. Удаление вашим способом

    Почему так происходит? Понимание приходит, если кодить не только в 1С, а например кодить в ООП, в Java. На самом деле при вашем способе создается НОВЫЙ объект, в который копируются данные из СТАРОГО объекта, причем при наличии ссылочных типов, идет нагрузка на процессор (можно почитать про коллекции в Java, там ясно объясняется разница между insert/delete с примитивными типами и object). Я не могу тут привести размеры ОЗУ и нагрузку на процессор (придется заморочится), но поверьте я часто работаю с большими данными и вообще я считаю наиболее оптимальным способом является удаление через запрос.

    Со всем уважением к вам! Ваши статьи лаконичны и самое главное практичны!

    Reply
  21. spacecraft

    (20) считаете вышеприведенные варианты равнозначными?

    «РабочаяТаблица.Индексы.Добавить(«КУдалению»);» Это ничего не говорит?

    А теперь провести тесты с этим кодов в обоих способах и без этого кода. Результаты изменились? Неожиданно?

    Reply
  22. Marik

    Я просто отметил, что быстрее будет удалить

    Наилучшим решением будет удаление по отбору по индексированной колонке

    А то что, без этой строки

    РабочаяТаблица.Индексы.Добавить(«КУдалению»);

    будет дольше, это и так понятно. С самого начала я отметил — удаление по отбору по индексированной колонке.

    Reply
  23. spacecraft

    (22)

    будет дольше, это и так понятно. С самого начала я отметил — удаление по отбору по индексированной колонке.

    А почему отказываете в индексации в другом примере? Где сказано, что в 69 обязательно не индексированная колонка?

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

    Вы нашли «неравные» условия и сравниваете.

    Рассматривая Ваше высказывание: «Наилучшим решением будет удаление по отбору по индексированной колонке», можно ответить:

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

    Но последнее предложение должно пониматься нормальным разработчиком по-умолчанию.

    Reply
  24. Marik

    (23)

    Хорошо вот вам равные условия:

     РабочаяТаблица.Индексы.Добавить(«КУдалению»);
    РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура(«КУдалению»,Истина));
    //найдСтр = РабочаяТаблица.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    //Для к = 0 По найдСтр.ВГраница() Цикл
    // РабочаяТаблица.Удалить(найдСтр[к]);
    //КонецЦикла;

    результат

    и соответственно

     РабочаяТаблица.Индексы.Добавить(«КУдалению»);
    //РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура(«КУдалению»,Истина));
    найдСтр = РабочаяТаблица.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    Для к = 0 По найдСтр.ВГраница() Цикл
    РабочаяТаблица.Удалить(найдСтр[к]);
    КонецЦикла;

    результат

    Reply
  25. Marik

    (23)

    Порадовало 🙂 автор пишет, что:

    Быстрее всего удаляются строки путем копирования оставшихся строк по условию, обратному к условию удаления

    которое оказывается на самом деле — это:



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

    Ну и конечно напоследок

    Но последнее предложение должно пониматься нормальным разработчиком по-умолчанию

    Я бы дописал



    Нормальные разработчики
    — это разработчики, у которых есть телепатическая супер сила. Это шутка :)! Да, я прочитал ссылку выше к задаче 69. И все равно считаю, что удалить моим способ быстрее и самое главнее надежнее. Представьте у вас в ТЗ ярды строк, способ предложенный автором на короткое время создаст 2 копии ТЗ с 2-кратным потреблением ОЗУ (на 1-ю и 2-ю ТЗ), потом конечно 1-я удалится. Но что если у вас ОЗУ на 2 ТЗ не хватит? Получите банально «Недостаточно памяти».

    Со всем уважением!

    Reply
  26. spacecraft

    (24) снова не то смотрите.

    Код:

    Процедура ОсновныеДействияФормыЗаполнитьТЗ(Кнопка)
    ТЗ.Колонки.Добавить(«Номер», Новый ОписаниеТипов(«Число»));
    ТЗ.Колонки.Добавить(«КУдалению»,Новый ОписаниеТипов(«Булево»));
    Для к=1 По 300000 Цикл
    СтрТЗ = ТЗ.Добавить();
    СтрТЗ.Номер = к;
    СтрТЗ.КУдалению = к%2 = 0;
    КонецЦикла;
    Сообщить(ТЗ.Количество());
    КонецПроцедуры
    
    Процедура ОсновныеДействияФормыАнализУдалениемСтрокТЗ(Кнопка)
    
    ТЗКопия = ТЗ.Скопировать();
    ТЗКопия.Индексы.Добавить(«КУдалению»);
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    найдСтр = ТЗКопия.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    Для к = 0 По найдСтр.ВГраница() Цикл
    ТЗКопия.Удалить(найдСтр[к]);
    КонецЦикла;
    ВремяЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах()-ВремяНачала;
    Сообщить(«Кол-во элементов: «+ ТЗКопия.Количество());
    Сообщить(«Время выполнения удалением: «+ ВремяЗамера);
    КонецПроцедуры
    
    Процедура ОсновныеДействияФормыАнализКопированиемТЗ(Кнопка)
    ТЗКопия = ТЗ.Скопировать();
    ТЗКопия.Индексы.Добавить(«КУдалению»);
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    ТЗКопия = ТЗКопия.Скопировать(Новый Структура(«КУдалению»,Истина));
    ВремяЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах()-ВремяНачала;
    Сообщить(«Кол-во элементов: «+ ТЗКопия.Количество());
    Сообщить(«Время выполнения копированием: «+ ВремяЗамера);
    КонецПроцедуры
    

    Показать

    Замеры:

    300 000

    Кол-во элементов: 150 000

    Время выполнения удалением: 2 014

    Кол-во элементов: 150 000

    Время выполнения копированием: 222

    Кол-во элементов: 150 000

    Время выполнения удалением: 2 000

    Кол-во элементов: 150 000

    Время выполнения копированием: 225

    Кол-во элементов: 150 000

    Время выполнения удалением: 1 973

    Кол-во элементов: 150 000

    Время выполнения копированием: 224

    Кол-во элементов: 150 000

    Время выполнения удалением: 2 025

    Кол-во элементов: 150 000

    Время выполнения копированием: 227

    Кол-во элементов: 150 000

    Время выполнения удалением: 1 989

    Кол-во элементов: 150 000

    Время выполнения копированием: 222

    Что-то еще нужно доказывать?

    Reply
  27. Marik

    (26)

    Ну что же, теперь понятно, почему у вас отличные результаты чем у меня

    вот как выглядит мой тест

    Процедура СформироватьРабочуюТаблицу()
    Запрос = Новый Запрос;
    Запрос.Текст =
    «ВЫБРАТЬ *, ЛОЖЬ КАК КУдалению……..»;
    
    РабочаяТаблица = Запрос.Выполнить().Выгрузить();
    
    Счетчик = 1;
    Для каждого ТС из РабочаяТаблица Цикл
    Если Счетчик = 1 Тогда
    ТС.КУдалению = Истина;
    Счетчик = 0;
    Иначе
    Счетчик = 1;
    КонецЕсли;
    КонецЦикла;
    
    РабочаяТаблица.Индексы.Добавить(«КУдалению»);
    Сообщить(РабочаяТаблица.Количество());
    КонецПроцедуры
    
    Процедура Кнопка1Нажатие(Элемент)
    СформироватьРабочуюТаблицу();
    найдСтр = РабочаяТаблица.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    Для к = 0 По найдСтр.ВГраница() Цикл
    РабочаяТаблица.Удалить(найдСтр[к]);
    КонецЦикла;
    Сообщить(РабочаяТаблица.Количество());
    КонецПроцедуры
    
    Процедура Кнопка2Нажатие(Элемент)
    СформироватьРабочуюТаблицу();
    РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура(«КУдалению»,Истина));
    Сообщить(РабочаяТаблица.Количество());
    КонецПроцедуры

    Показать

    я подаю на вход ТЗ из запроса, вы — нет….поэтому результаты тестов у нас разные

    Так что и я прав и вы правы…..

    Reply
  28. spacecraft

    (27)

    я подаю на вход ТЗ из запроса, вы — нет….поэтому результаты тестов у нас разные

    Это шутка такая? Не смешно.

    Процедура Кнопка1Нажатие(Элемент)
    СформироватьРабочуюТаблицу();
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    найдСтр = РабочаяТаблица.НайтиСтроки(Новый Структура(«КУдалению»,Истина));
    Для к = 0 По найдСтр.ВГраница() Цикл
    РабочаяТаблица.Удалить(найдСтр[к]);
    КонецЦикла;
    ВремяЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах()-ВремяНачала;
    Сообщить(РабочаяТаблица.Количество());
    Сообщить(«Время выполнения удалением: «+ ВремяЗамера);
    КонецПроцедуры
    
    Процедура Кнопка2Нажатие(Элемент)
    СформироватьРабочуюТаблицу();
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура(«КУдалению»,Истина));
    ВремяЗамера = ТекущаяУниверсальнаяДатаВМиллисекундах()-ВремяНачала;
    Сообщить(РабочаяТаблица.Количество());
    Сообщить(«Время выполнения копированием: «+ ВремяЗамера);
    КонецПроцедуры
    

    Показать

    Что покажет этот код?

    Reply
  29. Marik
    Reply
  30. Marik

    (28)

    ТекущаяУниверсальнаяДатаВМиллисекундах

    я тестирую на 1С 8.1 и смотрю через замер производительности

    Reply
  31. Marik

    (28)

    Опять же по поводу как формируется ТЗ. ТЗ можно формировать по разному, но вот удалить строки, как автор утверждает — быстрее всего ТАК!

    Ремарка к «Это шутка! Не смешно»

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

    69. Быстрое удаление строк в таблице значений

    Удаление строк в таблице значений

    Быстрее всего удаляются строки путем копирования оставшихся строк по условию, обратному к условию удаления:

    РабочаяТаблица = РабочаяТаблица.Скопировать(Новый Структура(«КУдалению», Ложь))

    Reply
  32. Marik

    (28)

    ОШИБОЧКА У меня 🙂 я неправильно выполнял тесты. Сейчас вижу, что был неправ!

    ВЫ правы коллега, я перепроверил еще раз — метод Автора быстрее.

    В споре рождается истина — рад был поспорить с вами.

    Единственно, все еще пока сомневаюсь — это расход ОЗУ.

    Со всем уважением!

    Reply
  33. pavlovsv

    Спасибо автору за интересные публикации.

    Хочу поделиться своей версией минимализма для задачи 57:

    ВЫБРАТЬ ПЕРВЫЕ 1

    КурсыВалют.Период,

    КурсыВалют.Валюта,

    КурсыВалют.Курс

    ИЗ

    РегистрСведений.КурсыВалют КАК КурсыВалют

    ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ

    МАКСИМУМ(КурсыВалют.Период) КАК Период,

    &ВалютаСсылка КАК Валюта

    ИЗ

    РегистрСведений.КурсыВалют КАК КурсыВалют

    ГДЕ

    КурсыВалют.Валюта = &ВалютаСсылка) КАК МаксПериодКурсаВалюты

    ПО (МаксПериодКурсаВалюты.Период > КурсыВалют.Период)

    И (МаксПериодКурсаВалюты.Валюта = КурсыВалют.Валюта)

    УПОРЯДОЧИТЬ ПО

    КурсыВалют.Период УБЫВ

    Протестировал оба варианта на таблице из 65 тысяч записей, этот вариант отрабатывает в два раза быстрее.

    Reply
  34. caponid

    Опять просмотрел все статьи… как всегда очень интересно, а местами забавно)

    но что то меня начали пугать «минимализмы» в запросах….

    Могу добавить в копилку: Знак числа

    Знак = (Ч>0)-(Ч<0) //1,0,-1
    Reply
  35. triviumfan

    70. Это точно работает?Если в переменных start и end задать «с 8 до 9», а с 9 до 10 интервал существует, то условие некорректно

    ГДЕ
    (РАЗНОСТЬДАТ(ЗаписиНаРемонт.НачалоВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(&КонечныйИнтервал, ЗаписиНаРемонт.НачалоВыполнения, СЕКУНДА) * РАЗНОСТЬДАТ(&КонечныйИнтервал, &НачальныйИнтервал, СЕКУНДА) <= 0
    ИЛИ РАЗНОСТЬДАТ(ЗаписиНаРемонт.НачалоВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(ЗаписиНаРемонт.ОкончаниеВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(ЗаписиНаРемонт.ОкончаниеВыполнения, ЗаписиНаРемонт.НачалоВыполнения, СЕКУНДА) >= 0)
    
    Reply
  36. ildarovich

    (35) Тестировал в свое время достаточно внимательно, работать должно

    sel ect * fr om tab
    where (@start — start) * (start — @end) * (@start — @end) <= 0
    or (@start — start) * (@start — end) * (start — end) >= 0;

    ГДЕ
    (РАЗНОСТЬДАТ(ЗаписиНаРемонт.НачалоВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(&КонечныйИнтервал, ЗаписиНаРемонт.НачалоВыполнения, СЕКУНДА) * РАЗНОСТЬДАТ(&КонечныйИнтервал, &НачальныйИнтервал, СЕКУНДА) <= 0
    ИЛИ РАЗНОСТЬДАТ(ЗаписиНаРемонт.НачалоВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(ЗаписиНаРемонт.ОкончаниеВыполнения, &НачальныйИнтервал, СЕКУНДА) * РАЗНОСТЬДАТ(ЗаписиНаРемонт.ОкончаниеВыполнения, ЗаписиНаРемонт.НачалоВыполнения, СЕКУНДА) >= 0)
    

    start = ЗаписиНаРемонт.НачалоВыполнения = 8
    end = ЗаписиНаРемонт.ОкончаниеВыполнения = 9
    @start = &НачальныйИнтервал = 9
    @end = &КонечныйИнтервал = 10

    Следовательно,

    РАЗНОСТЬДАТ(ЗаписиНаРемонт.ОкончаниеВыполнения, &НачальныйИнтервал, СЕКУНДА) == 0

    Вторая часть условия выполнится и из-за «или» станет истинным все условие.

    Получится, что интервалы пересеклись.

    Если хотите, чтобы они не пересекались, задайте значения

    end = ЗаписиНаРемонт.ОкончаниеВыполнения = 8:59:59, тогда у интервалов не будет общей секунды.

    Reply
  37. triviumfan

    (36) Неудобно отнимать секунду…

    Пришлось воспользоваться этой темой (где я также и ваше решение увидел в комментах).

    Заменил на

    ГДЕ
    (ЗаписиНаРемонт.НачалоВыполнения >= &НачальныйИнтервал
    И ЗаписиНаРемонт.НачалоВыполнения < &КонечныйИнтервал
    ИЛИ ЗаписиНаРемонт.ОкончаниеВыполнения <= &КонечныйИнтервал
    И ЗаписиНаРемонт.ОкончаниеВыполнения > &НачальныйИнтервал
    ИЛИ ЗаписиНаРемонт.НачалоВыполнения < &КонечныйИнтервал
    И ЗаписиНаРемонт.ОкончаниеВыполнения > &НачальныйИнтервал
    ИЛИ ЗаписиНаРемонт.НачалоВыполнения >= &НачальныйИнтервал
    И ЗаписиНаРемонт.ОкончаниеВыполнения <= &КонечныйИнтервал)
    

    Показать

    из первого примера:


    SET @start:=4;

    SET @end:=8;

    SEL ECT * FR OM `table`

    WHERE

    (`start` >= @start AND `start` < @end) /*смещение вперед*/

    OR

    (`end` <= @end AND `end` > @start) /*смещение назад*/

    OR

    (`start` < @end AND `end` > @start) /*вхождение — на самом деле здесь не обязательно оно обработается одним из предыдущих выражений*/

    OR

    (`start` >= @start AND `end` <= @end)/*поглощение и совпадение*/

    Показать

    Reply
  38. prime9

    Очень полено, спасибо 🙂

    Reply
  39. evgeni-red

    Спасибо! (51. Объединение пересекающихся периодов в запросе) — очень помогло для слияния периодов в запросе!

    Reply
  40. trustasia

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

    Reply
  41. ildarovich

    (41) Это интересно, готов к обсуждению

    Reply
  42. caponid

    44. Убрать префикс и лидирующие нули из номера

    Функция ЧислоСправа1(«ДП 046464») 

    ломается с эксепшином Преобразование значения к типу Число не может быть выполнено.

    Номер содержит пробелы.

    Reply
  43. ildarovich

    (43) Да, на пробелы в номере (?) или последний пробел в «префиксе» этот вариант не рассчитан. А, по вашему, должен был?

    Reply
  44. caponid

    (44) Пробелы в номере — это уже не номер) — или должен обговариваться как исключение.

    А вот пробел в префиксе (он же может быть произвольным) — это вполне нормально.

    Так что я за универсальность, и против ограничений (из-за неполноты решения) на входные данные.

    Reply

Leave a Comment

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