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




Принцип обмена данными из 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='\

42 Comments

  1. noblekey

    Можно так

    СтруктураОтбора = Новый Структура(«Наименование реквизита», Егозначение);// задаем условия

    МассивСтрок = ЭтотОбъект.Товары.НайтиСтроки(СтруктураОтбора);

    Для Каждого ЭлементМассив Из МассивСтрок Цикл

    ЭтотОбъект.Товары.Удалить(ЭлементМассив); //удаляем строки

    КонецЦикла;

    Reply
  2. Vitek

    Эта тема по моему уже затерта до дыр.

    Мне больше всего понравился способ от NS.

    Reply
  3. Ёпрст

    Автор, выкинь свой алгоритм в топку, смотри, как надо:

    http://www.sinor.ru/~my1c/knowhow/delstrtz.html

    Reply
  4. Ёпрст

    (2) Мне от TDV больше радует…

    Reply
  5. shard

    (1) под семерку не пойдет 😉

    (3) благодарю за ссылку

    Reply
  6. shard

    проверил код из темы в (3). неожиданно хороший результат по второму набору (все удовлетворяют условию)))). вывод — неплохо будет работать когда процент удаляемых значений мал из-за большого времени отработки строки «ТЗ.Удалитьстроку(сч);»

    Reply
  7. alexk-is
    Reply
  8. tsd

    а не проще таблицу с конца обходить?

    всего=ТЗ.Количествострок();

    пока всего > 0 цикл

    ТЗ.Получитьстрокупономеру(Всего);

    Проверка условий ….

    Всего = Всего -1;

    КонецЦикла;

    Reply
  9. alexk-is

    (8) В коде проще, но не быстрее. Самый быстрый и "правильный" из известных мне "alexk v.2"

    А самый простой по коду ниже:

    Код
    Для Индекс = -ТЗ.КоличествоСтрок() По -1 Цикл
        ТЗ.ПолучитьСтрокуПоНомеру(-Индекс);
        Если <ПроверкаУсловий> Тогда
            ТЗ.УдалитьСтроку();
        КонецЕсли;
    КонецЦикла;
    

    Показать полностью

    Reply
  10. Если скорость не очень важна, то можно юзать универсальную функцию из библиотеки функций.

    //fixin 200707072

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

    //ТЗ — таблица значений

    //Код — код проверки условия, например «Р=Стр.Статья<>П»

    //П — один или несколько (структура) параметров

    //При проверке условия в переменную Р нужно вернуть результат (истина — удалять, ложь — не удалять),

    // при этом доступна текущая строка СТР и переданный параметр Т.

    Функция обУдалитьСтрокиТЗПоУсловию(ТЗ, Код, П=Неопределено) Экспорт

    Всего=ТЗ.Количество();

    Для Инд=1 По Всего Цикл

    Поз=Всего-Инд;

    Стр=ТЗ[Поз];

    Р=ложь;

    Выполнить(Код);

    Если Р=истина Тогда

    ТЗ.Удалить(Поз);

    КонецЕсли;

    КонецЦикла;

    Reply
  11. alexk-is

    (12) Кроме того, что при удалении строки переписывается все последующие строки, так тут еще и компиляция «Код» в цикле.

    …еще один образец того «как делать не надо»…

    Reply
  12. O-Planet

    (7) 0_о Это релиз для NASA метода удаления строк из таблиц?

    Reply
  13. maljaev
    Reply
  14. maljaev

    В последнем примере комментарий неверно сформулировал. Надо читать так:

    Код
    // отфильтровать ТЗ по заданному сотруднику, фирме, и с окладом более 5000 рублей
    

    Показать полностью

    Reply
  15. Vitek

    Статья стала полезной однако, после того как отцы комментов накидали 🙂

    Плюс!

    Reply
  16. Jogeedae

    Можно фильтровать ТЗ по точному значению

    //ПараметрыОтбора = новый Структура;

    //ПараметрыОтбора.Вставить(сИмя,сЗнач);

    //где сИмя — колонка, сЗнач — значение отбора

    ТЗ = ТЗ.Скопировать(ПараметрыОтбора);

    Reply
  17. SunShinne

    Спасибо! Очень помогло. Обычный способ в 1С действительно глючит

    Reply
  18. CheBurator

    какой-такой «обычный» способ..?

    .я тут вчера кучу времени убил.. — две ТЗ, вроде как одинаковые даже по составу данных (колонки артикул и колво, сортируем по Артикул), сравниваю путем преобразования в строку… ан нет.. то что совершенно одинаково видится как визуальная ТЗ — при ЗначениеВстроку(ТЗ) — получается совсем не отсортированной!

    Reply
  19. CheBurator

    пользуюсь вот такими…

    //******************************************************************************

    // ОчисткаТЗ()

    // Параметры: ТЗ, которую надо очистить

    // В ТЗ д.б. Колонки с идентификаторами «НадоУдалить» и «ОПС» (оригинальный порядок строк)

    // Описание: очищает ТЗ от ненужных строк

    Процедура глОчисткаТЗ(ТЗдляЧистки, ОПС=»+ОПС», КолонкаУдалить=»НадоУдалить», Режим=0) Экспорт

    Попытка НадоУдалить = ТЗдляЧистки.Итог(КолонкаУдалить);

    Исключение Возврат;

    КонецПопытки;

    ТЗКС = ТЗдляЧистки.КоличествоСтрок();

    Если Режим <> 0 Тогда

    Сообщить(«> [«+ТекущееВремя()+»]: *** удаляем «+НадоУдалить+» из «+ТЗКС+» ****»);

    КонецЕсли;

    Если НадоУдалить <= 0 Тогда Возврат; КонецЕсли;

    Если НадоУдалить >= ТЗКС Тогда

    ТЗдляЧистки.УдалитьСтроки();

    Иначе

    ТЗРаб = СоздатьОбъект(«ТаблицаЗначений»);

    ТЗдляЧистки.Выгрузить(ТЗРаб);

    ТЗРаб.Сортировать(«+»+КолонкаУдалить);

    ТЗРаб.Выгрузить(ТЗдляЧистки,1,ТЗКС-НадоУдалить);

    ТЗРаб = 0;

    КонецЕсли;

    Если ОПС = «###» Тогда Возврат; КонецЕсли; //сортировать не надо

    //восстановим оригинальный порядок строк

    ТЗдляЧистки.Сортировать(ОПС);

    КонецПроцедуры //глОчисткаТЗ()

    Reply
  20. CheBurator

    //————————————————————————————

    Функция глОтобратьПоКолонке(ТЗВход,Колонка,Значение) Экспорт

    //возвращает отобранную ТЗ

    Перем ТЗ, ТЗВрем;

    ТЗВход.Выгрузить(ТЗ);

    ТЗ.Сортировать(Колонка+»*»); //по внутр значению

    НомСтр = 0;

    Если ТЗ.НайтиЗначение(Значение, НомСтр, Колонка) = 0 Тогда

    //нет такого значения

    ТЗ.УдалитьСтроки();

    Возврат ТЗ;

    Иначе

    //найдем строку, в которой уже не встречается Значение

    ТЗКС = ТЗ.КоличествоСтрок();

    Для счСтрок = НомСтр По ТЗКС Цикл

    Если ТЗ.ПолучитьЗначение(счСтрок, Колонка) <> Значение Тогда

    //нужное значение есть до пред.строки

    НомСтр2 = счСтрок — 1;

    Прервать;

    КонецЕсли;

    Если счСтрок = ТЗКС Тогда

    //нужное значение встречается до конца таблицы

    НомСтр2 = ТЗКС;

    КонецЕсли;

    КонецЦикла;

    КонецЕсли;

    ТЗВрем = СоздатьОбъект(«ТаблицаЗначений»);

    ТЗ.Выгрузить(ТЗВрем,НомСтр,НомСтр2); //выгрузим только строки с нужным значением

    Возврат ТЗВрем;

    КонецФункции //глОтобратьПоКолонке()

    Reply
  21. Luck_DMST

    Ну а как же простое удаление?

    Например, почистить список контрагентов от которых не было оплаты

    НайденныеСтроки = ОплатаФакт.НайтиСтроки(Новый Структура(«Сумма», 0));
    Для каждого СтрокаТЧ Из НайденныеСтроки Цикл
    ОплатаФакт.Удалить(СтрокаТЧ);
    КонецЦикла;
    
    Reply
  22. Parazyte

    (21) Luck_DMST, эт ты обознался, тут люди за семёрку гутарят.

    Вообще на Мисте ИМХО наилучший вариант


    А вот еще один правильный алгоритм, предложенный Wlad:

    ТабЗнач.Выбратьстроки();

    Пока ТабЗнач.ПолучитьСтроку()=1 Цикл

    Пока (<условие>) и (ТабЗнач.НомерСтроки<>0) Цикл

    ТабЗнач.УдалитьСтроку(); //следующая строка стала текущей

    КонецЦикла;

    КонецЦикла;

    Reply
  23. shard

    (22) Parazyte, а на быстродействие проверяли?

    Reply
  24. Parazyte

    Нет, но это будет играть роль имхо при оооочень больших таблицах

    Reply
  25. Luck_DMST

    (22) Простите, на заголовок не обратил внимания т.к. открыты были только комментарии и как раз занимался удалением строк в ТЗ

    Reply
  26. binx

    (12) O-Planet,

    ТЗСтроки = ТЗ.НайтиСтроки(ПараметрыОтбора);
    Для каждого СтрокаУдаления Из ТЗСтроки Цикл
    ТЗ.Удалить(СтрокаУдаления);
    КонецЦикла;
    

    Reply
  27. Cooler

    (26) «Ты быстр!» (с)

    Reply
  28. Sanario

    Как раз искал

    Reply
  29. FraerFFSG

    У меня

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

    НЕ РАБОТАЕТ ни один ВАРИАНТ!

    Reply
  30. shard

    (29) FraerFFSG, обратите внимание на 16й комментарий.

    по коду — может быть надо

    Для каждого Элемент из ВыборРода Цикл
    НайденныеСтроки = ТЗВесьОтчет.НайтиСтроки(Новый Структура(«РодВагона», Элемент));
    Reply
  31. SLukin

    СтрокиПоКонтрагенту = ТЧДокумента.Скопировать();
    
    Индекс = СтрокиПоКонтрагенту.Количество() — 1;
    Пока Индекс >= 0 Цикл
    Если СтрокиПоКонтрагенту[Индекс].Договор.ТипДоговора = Перечисления.ТипыДоговоров.СПоставщиком Тогда
    СтрокиПоКонтрагенту.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс — 1;
    КонецЦикла;
    

    Показать

    Reply
  32. Qwest_IS

    А Запрос к ТЗ это плохо?

    Reply
  33. feka88

    Сделал вот так:

    КолСтрок = ТаблицаПользователей.Количество();
    СчетчикСтрок = 1;
    
    Пока СчетчикСтрок < КолСтрок Цикл
    
    СтрокаТЗ = ТаблицаПользователей.Получить(СчетчикСтрок);
    
    ПараметрыПоискаСтрок = Новый Структура;
    ПараметрыПоискаСтрок.Вставить(«ИдентификаторПользователяИБ», СтрокаТЗ.ИдентификаторПользователяИБ);
    МассивСтрок = ТаблицаПользователей.НайтиСтроки(ПараметрыПоискаСтрок);
    КолОдинаковых = МассивСтрок.Количество();
    
    Если   КолОдинаковых > 1   Тогда
    
    ТаблицаПользователей.Удалить(СчетчикСтрок);
    КолСтрок = КолСтрок -1;
    
    Иначе
    СчетчикСтрок = СчетчикСтрок+1;
    
    КонецЕсли;
    
    Конеццикла;

    Показать

    Reply
  34. AnnaKalacheva

    Мне больше всего нравится такой вариант

    УдалитьТП=Новый Массив;
    Для каждого Строка из ТЗ_ТП Цикл
    Если Строка.Валюта.Код<>»974″ Тогда
    УдалитьТП.Добавить(Строка);
    КонецЕсли;
    КонецЦикла;
    
    Для каждого Строка из УдалитьТП Цикл
    ТЗ_ТП.Удалить(Строка);
    КонецЦикла;

    Показать

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

    Reply
  35. AnnaKalacheva

    Еще вариант

    Сч=0;
    Пока Сч < ТЗ.Количество() Цикл
    Если ТЗ[Сч].Номер=1 Тогда
    ТЗ.Удалить(Сч);
    Иначе
    Сч=Сч+1;
    КонецЕсли;
    КонецЦикла;
    

    Показать

    Reply
  36. alex-l19041

    (32) Qwest_IS, почему плохо ???

    Reply
  37. alex-dp

    Здесь в Результат ишется 0 в поле Количество и удаляет все Количество=0 :

    НайденнаяСтрока = Результат.Найти(0, «Количество»);

    Пока НайденнаяСтрока <> Неопределено Цикл

    Результат.Удалить(НайденнаяСтрока);

    НайденнаяСтрока = Результат.Найти(0, «Количество»);

    КонецЦикла;

    как по мне самый понятный вариант.

    Reply
  38. Sph1nX

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

    Reply
  39. shard

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

    Reply
  40. insurgut

    (9) т.к. очень часто использую ваш алгоритм, когда нужно удалить строки по условию в ТЧ за один проход и постоянно переделываю его под 8-ку, то позволю себе выложить чуть измененный код, чтобы в дальнейшем копировать его без переделки 🙂

    Для Индекс = -Объект.ТЗ.Количество()+1 По 0 Цикл
    Если Объект.ТЗ[-Индекс].Значение = <Условие> Тогда
    Объект.ТЗ.Удалить(-Индекс);
    КонецЕсли;
    КонецЦикла;
    Reply
  41. dobrynin.i.s

    Я просто выгружаю нужные столбцы из таблицы по отбору

    ПараметрыОтбора = Новый Структура;

    ПараметрыОтбора.Вставить(«Обработать», истина);

    НоменклатураБазы=Объект.НоменклатураБазы.Выгрузить(ПараметрыОтбора,»Колонка1,Колонка2,….,КолонкаN»);

    Reply
  42. user764709

    (1)

    МассивСтрок = ЭтотОбъект.Товары.НайтиСтроки(СтруктураОтбора);

    Для Каждого ЭлементМассив Из МассивСтрок Цикл

    ЭтотОбъект.Товары.Удалить(ЭлементМассив); //удаляем строки

    КонецЦикла;

    Очень помогло, спасибо)

    Reply

Leave a Comment

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