<?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='\
(0) Просто, грамотным языком и ненавязчиво. Только это 0,01%. Остальное — опыт, практика, тестирование
Спасибо за статью! Так держать! 🙂
(1) Насчет ненавязчиво я бы поспорил.
Первый пример вообще ни к селу ни к городу.
Автор по-видимому считает, что при логическом умножении логического значения «Ложь» на что угодно, хоть на стеариновую свечку, должна таки ложь получиться.
Девятый и десятый примеры. Всякому известно, что пустое множество является подмножеством любого множества. А в ЖКК условие вхождения описывается именно в терминах множеств.
Двенадцатый пример — вообще ни о чем. Понятно же, что сортировка по значению элемента справочника бессмысленна, ибо неповторяема. «Сортировка» будет такой же, как в восьмерочной выборке ДЛЯ КАЖДОГО…
Тринадцатый пример основан на неявном предположении автора о том, что строка и представление строки — это одно и то же. Если из этого неверного предположения не исходить (а с какой стати?), то текст опять-таки оказывается ни о чем.
(3) Арчибальд не дремлет…
С замечаниями согласен. Тема хорошая и нужная для начинающих 1С-ников.
(4) Заметь, минуса я не поставил, хотя первый пункт меня сильно напряг. 😀 Все же пользы от статьи больше, чем вреда.
(3)
Программист, когда пишет логическое выражение, ожидает, что его результатом будет либо «Истина», либо «Ложь», а вовсе не «стеариновая свечка» в виде ошибки программы. И он ожидает, что если первый сомножитель «Ложь», то дальше уже проверять незачем. И в 8-й версии 1С:Предприятие это поведение исправлено.
Если Вы внимательнее прочтёте 10-й пункт, то увидете, что ситуация неоднозначна (ошибочна): 1С то считает, что пустое значение входит в список, и одновременно (для каких-то условий и функций) не считает.
неповторяема. «Сортировка» будет такой же, как в восьмерочной выборке ДЛЯ КАЖДОГО…
В 1С 7.7 сортировка по значению элемента справочника вовсе не бессмысленна. Как я написал в статье: «Таблица значений сортируется по колонке с элементами справочника по их основному представлению».
Тринадцатый пункт о том, какую именно сортировку мы получим в различных случаях. И если Вы считаете, что всё это очевидно, то я удивлён.
(6)
Т.е. в восьмерке правильным будет написать
Если Истина ИЛИ 8 Тогда
Программист не должен ожидать. Он должен обеспечить, чтобы операнды всех логических операций были логическими. Если он не обеспечил — это его ошибка.
Ситуация как раз однозначна: некорректное написание условия породило некорректную его обработку.
Сортировка по значению справочника, естественно, происходит по основному представлению. Но если я пишу универсальную обработку, я не знаю каково будет это основное представление в момент запуска, т.е. я не имею права делать об этом какие-либо предположения. Возьму назад только термин «бессмысленна». Вместо него следует читать «некорректна/ошибочна».
Тринадцатый пункт не дает ответа на вопрос, как именно сортируются объекты-строки. Кое-какие частичные наблюдения. Поскольку полного представления об этом нет, результат сортировки непредсказуем, и значит, хороший программист не сможет ей воспользоваться.
Первый пункт четко и точно описан в ЖКК, значит, это не баг, а фича.
Это известная фича 1С 77.
(7)
В приведённом в статье примере оба операнда логические:
Если (Док.Вид()=»ПриходнаяНакладная»)
И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) Тогда
Но при этом в 1С 7.7 мы можем наступить на «грабли», если документ Док не имеет реквизита ПризнакНакладной, а в 1С 8 этой проблемы уже нет. И я не пишу, что это ошибка 1С, а пишу, что это особенность обработки сложных логических выражений. Мне непонятно, что Вам не нравится.
А я разве предлагаю всегда сортировать по самому элементу справочника? Я пишу про особенность сортировки таблицы значений, когда сортируем по колонке с элементом справочника. В большинстве случаев представление нам известно. Если мы отсортируем явным образом по наименованию, то можем получить неприятность при одинаковых наименованиях. И это достаточно очевидно. А речь в статье как раз идёт о том, что отсортировав по самому элементу справочника, мы можем получить ту же неприятность, что несколько менее очевидно.
В чём некорректность этого условия?
Условие (НЕ(ВидОтгрузки в СписокВидовОтгрузки));
А я в самом начале написал: «Настоящая статья не претендует на полноту описания и подробный анализ ошибок и «подводных камней» встроенного языка платформы 1С:Предприятие 7.7». Я не теоретик, я описал реальные случаи, с которыми пришлось столкнуться на практике. И это описание (в сокращённом виде, конечно) использовал раньше сам для себя, чтобы не наступать на одни и те же «грабли». И надеюсь, кому-то это тоже пригодится. А в тринадцатом пункте как раз описаны все самые распространённые случаи.
(9) (Док.ПризнакНакладной = Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) — это операнд неопределенного типа, поскольку сравнивать можно лишь однотипные значения, а значение слева вовсе не обязано иметь тип перечисления, что справа. И если в восьмерке такой финт проходит, то это ошибка восьмерки. Выражение «(1=1) ИЛИ 8» не должно проходить синтаксического контроля. В очередном релизе платформы фирма 1С имеет полное право ошибку исправить…
ИМХО, большая часть описанного проистекает не из «ошибок и особенностей реализации», а из неряшливости программирования.
(10)
Это Ваше выражение, а не моё. А вот выражение «(1=1) ИЛИ МояПеременная» всегда будет проходить синтаксический контроль и всегда будет давать «Истина» в 1С 8, в отличие от 1С 7, вне зависимости от значения переменной МояПеременная.
(3)
А вот программисты 1С 7.7 не пришли в этом вопросе к полному консенсусу (по крайней мере в релизе 25).
Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));
Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);
Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.
(10)(11) Господа, Вы спорите по одной простой причине: в языке 1С нет операторов && и ||. Разработчики других языков (например того же PERL) не считают себя самыми умными.
Бинарное || — логическое ИЛИ. Если левый аргумент TRUE, то правый аргумент не проверяется.
(0) Маленькая справка по первому пункту:
В 1С 8 не возникнет ошибки не потому, что второй операнд проигнарируется, а потому, что будут сравнивается на равенство типы. Более подробно об этом можно почитать в синтекс-помошнике.
(13) Цитата из документации «1С:Предприятие 8.1. Конфигурирование и администрирование», страница 1-251:
===========================
Замечание. При вычислении логического выражения вычисляются только необходимые части выражения. Например, в выражении (Цена > 0) И ПроверкаСуммы(), если Цена <= 0, то функция ПроверкаСуммы() не вызывается.
===========================
AleksR хорошая полезная статья.
Арчибальд критика была не по существу.
(14)
… даже и в том случае, когда функция ПроверкаСуммы() имеет результат не логического типа или вообще дает ошибку при вычислении. Неряшливый программист — семерочник из первого примера эту ошибку увидит сразу. Неряшливый программист — восьмерочник может долго еще думать, что он все правильно написал. Грамотный программист озаботится тем, чтобы оба операнда логического выражения были логическими.
(16) Не стоило бы, наверное, так строго судить… Автору — спасибо за заботу, 1С-ке — минус за глюки! 🙂
Вы, наверное, тоже могли бы поделиться чем-то аналогичным из своего огромного опыта 1С-программинга…
З.Ы. Несколько лет назад 1С даже рассылала некий бюллетень ошибок, найденных пользователями,
правда быстро прекратила — после того, видимо, как его объем вырос за примерно полгода до нескольких сотен строк… 🙂
Не стоило бы, наверное, так строго судить… Автору — спасибо за заботу, 1С-ке — минус за глюки!
Зачем изначально программировать плохо? То что в 8-ке такая байда проходит, не делает чести ни ей, ни неряшливому программиста.
А вдруг на смену 1С-ке придет что-то лучшее? И тяжело будет этому кодеру писать правильно.
(18) В 1С 7.7 приходилось писать:
———————
Обрабатывать=0;
Если Док.Вид()=»ПриходнаяНакладная» Тогда
Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя Тогда
Обрабатывать=1;
КонецЕсли;
ИначеЕсли Док.Вид()=»РасходнаяНакладная» Тогда
Если Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Обрабатывать=1;
КонецЕсли;
КонецЕсли;
Если Обрабатывать=1 Тогда
…
КонецЕсли;
———————
А в 1С 8 можно написать:
———————
Если ((Док.Вид()=»ПриходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя))
ИЛИ ((Док.Вид()=»РасходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику))
Тогда
…
КонецЕсли;
———————
Вы действительно считаете второй вариант «неряшливым»? И действительно в 1С 8 всегда создаётеь громаздьё конструкций «Если»?
(19) Я просто считаю, что логические операции И и ИЛИ коммутативны. И в семерке это так. Вы же вместе с разработчиками платформы восьмерки это отрицаете.
(20) Подход к вычислению логических выражений, реализованный в 1С 8, кроме повышения быстродействия, позволяет создавать более короткий и более «читаемый» код. Пример я привёл выше. Кстати, это вовсе не изобретение 1С 8. В MS Fortran и FoxPro, на которых я работал до 1С, был реализован точно такой же подход. Поэтому для меня «лишние» вычисления в логическом выражении оказались в 1С 7 неприятным сюрпризом.
(19) не надо путать громоздкость кода с неряшливым подходом к вычисляемым условиям
(21) Да, код получается более коротким. Но не более читаемым — наша дискуссия тому доказательство.
Этот способ сокращения записи имеет право на существование, однако ж при чтении надо понимать, что краткость достигается за счет правильного понимания ненаписанного. А именно: в логических выражениях в восьмерке (и ряде других языков) отключен (частично) контроль корректности вычислений. Это фича (особенность реализации) таких языков, специально упоминаемая в описании языка. Отсутствие такого упоминания автоматически означает, что типы операндов контролируются путем вычисления.
На этапе составлении алгоритма я считаю некорректным использование особенностей реализации языка — тогда из «программиста» превращаешься в «программиста 1С8» или «программиста ФоксПро». Ну, а в первом примере «программист» и «программист 1С7.7» совпадают.
Я тоже встречал ошибки: 1с по-разному работает под sql и под dbf:
— На скуле некорреткно работают запросы когда в них выбираются через точку реквизиты какого-либо справочника, причем в запросе обращение к этому справочнику стоит 2 и более раз.
— Почему то по оборотным счетам в базе на скуле хранятся в том числе и остатки.
(23) Дискуссия идет «вот уже пятые сутки», и я не вытерпел…
В логических выражениях в восьмерке (и ряде других языков) отключен (частично) контроль корректности вычислений.
Это фича (особенность реализации) таких языков, специально упоминаемая в описании языка.
Отсутствие такого упоминания автоматически означает, что типы операндов контролируются путем вычисления.
На этапе составлении алгоритма я считаю некорректным использование особенностей реализации языка
Считаю, что спор пошел уже совсем
ни о чемне о том, поскольку:— «ряд других языков» есть на деле большинство языков; ИМХО неполное вычисление логического выражения применяется в 1С8, Фортране, С и С++, полное в 1С7 и Visual Basic, счет 4:2;
— не «отключен контроль корректности вычислений», а отсутствует строгая типизация и широко распространено приведение типов, в том числе и неявное, из-за чего о контроле корректности вычислений без выполнения этих самых вычислений лучше не вспоминать;
— упоминание о таком способе вычисления логических выражений как о фиче в отношении языка 1С8 имеется, что было показано в посте 14;
— этап составления алгоритма уж давно прошел, а на этапе написания программы на конкретном языке правильное использование особенностей реализации этого языка очень даже похвально;
— и, кстати, на коммутативность логических операций это никоим боком не посягает, а выражение «(1=1) ИЛИ 8» синтаксически абсолютно верно, и только семантически с ним (возможно) что-то не так.
(25)
Более правильно сказать, что в ряде компиляторов (именно компиляторов, а не языков) — MS VC++, C++ Builder и т.п. есть настройка (включаемая пользователем), которая позволяет вычислять логические выражения неполностью.
Так как вычисление полностью нередко бывает необходимо на этапе отладки программ, чтобы максимально быстро выявить все ошибки.
А вот когда автор узнает про * в параметрах сортировки, то не будет писать бреда типа этого:
Табл.Сортировать(«Клиент,КлиентКод»);
+27 и тем более, не нужно лепить новую колонку для сортировки.
Как всегда, в таких статьях — комменты рулят!)
Обход проблемы в п. 4:
«Условие (ВыбКлиент.Принадлежит(Клиент)=1);»
— «ряд других языков» есть на деле большинство языков; ИМХО неполное вычисление логического выражения применяется в 1С8, Фортране, С и С++, полное в 1С7 и Visual Basic, счет 4:2;
1. При чем тут счет?!
2. Вы всего о 6 языках слышали? 😀
Обход проблемы в п. 4:
«Условие (ВыбКлиент.Принадлежит(Клиент)=1);»
Так нельзя. Общее правило для фильтров: если он не установлен (список значений ВыбКлиент пустой), то условие должно быть истинно.
(27) Цель — отсортировать таблицу значений по наименованию, но так чтобы не оказались строки с разными элементами справочника, но одинаковыми наименованиями вперемешку. А при сортировке по внутреннему значению получим рядом все строки, относящиеся к одному элементу справочника, но упорядочивания по элементам вообще никакого не будет.
(32) Ё.. как дети.
Табл.Сортировать(«Клиент+,Клиент*»);
(33) Согласен. Так действительно лучше.
Это, на мой взгляд, первое дельное замечание по содержанию статьи.
>>>3. Ошибка запроса по месяцам
Брехня.
+35 есть ВСЁ.
>>>4.
Аналогично — всё работает.
ЗЫ: максимум, на SQL базе не всегда работает — а именно, если в списке 1 элемент , то фильтр игнорируется.
+37
>>7.
Тоже бред. Функция всегда рассчитывается верно, если статус — измерение регистра.
Мот ты условия на реквизит регистра накладываешь ?
:))))))))))
Единственное — в запросе используется уп
Ёпрст, где ты раньше был? 🙂
>>>3. Ошибка запроса по месяцам
Брехня.
Отсутствие ошибки в непонятно каком релизе платформы в непонятно каком формате базы вовсе не означает, что её не было в 17-м релизе DBF-базы. Не исключено также, что ошибка может наблюдаться при дополнительных условиях, которые были в реальном запросе.
(40) з@ебись .. Мот тебе еще и все ошибки всех древних релизов перечислить ?
Их есть у меня.
(40)
что её не было в 17-м релизе DBF-базы
а в в 25 или 27 релизе она есть?
(38) Это чего — теоретические рассуждения? Логических ошибок в этих запросах нет — они есть в реализации на платформе 1С 7.7 и конкретно наблюдались в 25 релизе на SQL-базе.
А об этом я уже писал:
Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));
Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);
Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.
Это не в теории, а в конкретной практике.
По поводу того какая проблема к какому релизу — имхо лучше это написать не в шапке, а прямо в проблеме.
(43)
Это не в теории, а в конкретной практике
Если практика конкретная — проблема 1-5 осталась в 25 релизе? а в 27?
P.S. Очень хочется снести эту публикацию — по-моему, от нее вреда больше чем пользы.
Жалко только что комменты Арчибальда и Ёпрста погибнут вместе с ней.
(40) В самом начале статьи я написал, какая проблема обнаружена в каком релизе и в каком формате базы, и предложил проверить всем желающим актуальность для последнего релиза.
Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));
Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);
Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.
Это не в теории, а в конкретной практике.
Тебе еще раз говорят — пустое значение является элементом любого множества.
Да и, открой профайлер наконец.
(45) А тебе ещё раз говорят: в конкретной практике «функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае».
(46) Мало кто видит для какого она релиза, это же надо каджый раз вверх подниматься
(48) Я внесу уточнения в статью.
Программный код в тексте публикации можно былораскрасить более простым способом 🙂
(50) Какое ожесточение? Ни я, ни Ёпрст (основные критики) минусом к статье не отметились, продемонстрировав тем самым свою толерантность. А вот автору следовало бы часть высказанных замечаний внести в текст статьи — не каждый полезет в обсуждение, и останется в результате весьма далек от истины.
(52)
Я в ближайшее время собираюсь сделать вариант статьи с дополнительными пояснениями. Однако ложных высказываний в статье пока не обнаружено.
(38)
Это неверное утверждение. В математике правильно так: пустое множество является подмножеством любого множество.
Причём пустое множество — это множество, не содержащее ни одного элемента.
Таким образом, элемент со значением 0 не принадлежит множеству {1; 2; 3}. Полный аналог пустого множество — это NULL в 1С 8.
(51) А я и раскрашивал с помощью Вашей обработки «Разукрашка». Очень удобно. Спасибо ещё раз! Просто я результат раскраски вставлял в статью в Word. А уже всю статью из Word через буфер обмена копировал в поле описания публикации.
(55) Вот я и смотрю, что код HTML страшнее страшного.
(54) ЖКК, стр. 823:
Речь идет именно о двух множествах, одно из которых является/не является подмножеством другого, а не о вхождении элемента в множество.
Разумеется, описание невнятное. Но это лишь повод для того, чтобы программист обеспечил однозначность толкования вхождения путем контроля А и Б.
Пример: ПолучитьПустоеЗначение() принадлежит {1; 2; 3}, а ПолучитьПустоеЗначение(«Число») — не принадлежит. ПолучитьПустоеЗначение() — это полный аналог NULL в 1С 8…
(57) В пункте 9 статьи, о котором и идёт спор, на вхождение в список проверяется КодОперации, являющийся реквизитом регистра. И он имеет вполне определённый тип. И проверяться на вхождение будет не абстрактное ПолучитьПустоеЗначение(), а вполне конкретный » » (пробел), если КодОперации имеет тип строки длиной 1.
(58) А вот в этом конкретном месте ляп имеется.
В ЖКК имеется указание на то, что для строк ПустоеЗначение() работает как ПустаяСтрока(). На мой взгляд, эта фича весьма вредна. Разумным было бы результатом функции ПустоеЗначение(» «) иметь 0. Хотя бы потому, что СтрДлина() прекрасно считает пробелы.
Скуль, насколько мне известно (не уверен), пробельную строку пустым значением не считает.
(59) В чём ляп? Как вы сами согласились, 1С считает пробельную строку тоже пустым значением. Поэтому в статье я и употреблял этот термин, как наиболее общий. Не важно, какой тип у реквизита КодОперации. Но для каждого типа есть своё пустое значение. И это не NULL в данном примере.
(60)
В данном случае, не одно пустое значение.
ПустоеЗначение(» «) = 1
но
» » <> ПолучитьПустоеЗначение(«Строка»);
Вот я и считаю, что здесь 1С допустила ляп.
Я согласен, что 1С достаточно вольно обращается с пробелами. Но речь-то идёт о другом. Согласитесь всё же, что Ваше замечание:
некорректно по сути, так как в 9-м и 10-м примерах нет пустого множества, а есть пустые значения и это не одно и то же.
(62) Потому я в 57 посте и процитировал ЖКК: «Значение А является подмножеством значения Б». Очень коряво. Когда Б — СписокЗначений, напрашивается вывод, что и А должно как-то преобразовываться в список. И еще вопрос, если А — пустое значение, будет ли оно преобразовано в пустой список, либо в список, состоящий из одного пустого значения. К тому же списки длины 1 вообще ведут себя в запросах коряво.
(63) Если и преобразуется, то в список из одного пустого значения. Как я уже дважды писал:
Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);
Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется. И это, на мой взгляд, не ошибка 1С. А ошибка, когда при условии «НЕ(КодОперации в СписокКодовОпераций)» тоже не выполняется. И в ряде других запросов, которые я приводил, проблемы происходят при условии отрицания. В 10-м пункте я описал реальную ситуацию, с которой столкнулся, когда не выполняются лишь некоторые функции и лишь при некоторых условиях. Когда же отрицания нет, то с такими проблемами я не сталкивался.
Не поленился проверить:
Б = СоздатьОбъект(«СписокЗначений»);
Б.ДобавитьЗначение(1);
Б.ДобавитьЗначение(2);
Б.ДобавитьЗначение(0);
А = 0;
Условие (А в Б) = Ложь
А = ПолучитьПустоеЗначение(«Число»);
Условие (А в Б) = Ложь
А = ПолучитьПустоеЗначение();
Условие (А в Б) = Истина
Вот так как то… Для ДБФ. А в скуле — не так…
(65) А как именно Вы проверяли Условие (А в Б)? Я проверил то же самое с помощью метода Принадлежит():
Б.Принадлежит(А)
и получил противоположный результат:
значение принадлежит данном списку в первых двух случаях (когда А=0 и А=ПолучитьПустоеЗначение(«Число»)) и НЕ принадлежит в последнем (когда А=ПолучитьПустоеЗначение()).
Если же в списке нет элемента со значением 0, тогда все три вышеуказанные значения НЕ принадлежат списку.
Из описания встроенного языка системы 1С:Предприятие 7.7:
«Метод Принадлежит проверяет вхождение в список значений заданного значения. Другими словами, оператор Список.Принадлежит(ВыбДок) проверяет, является ли значение ВыбДок подмножеством списка значений Список.»
Таким образом, ПолучитьПустоеЗначение() тоже не является пустым множеством. Согласно документации, это пустое значение неопределённого типа.
Проверялось в релизе 27 и формате базы данных DBF.
(65) +66 Сейчас потестил как запрос работает для двух вариантов условий:
Условие (А в Б);
Условие (НЕ(А в Б));
для двух вариантов списка значений Б:
{1; 2; 0}
{1; 2}
и для трёх вариантов значений А:
0
ПолучитьПустоеЗначение(«Число»)
ПолучитьПустоеЗначение()
Для значений 0 и ПолучитьПустоеЗначение(«Число») все результаты одинаковы, что подтверждает эквивалентность этих значений. Дальше для краткости буду писать только про значение 0.
Из результатов запросов следует, что с точки зрения реализации запроса значение 0 не является подмножеством множества {1; 2}, что, на мой взгляд, логично. Однако, как Вы и писали, оно также не является подмножеством множества {1; 2; 0}, что уже совсем нелогично. Для значения ПолучитьПустоеЗначение() получается вообще полный бред: условие истинно для всех четырёх вариантов, т.е. ПолучитьПустоеЗначение() является подмножеством обоих множеств (это можно было бы трактовать как то, что ПолучитьПустоеЗначение() — это пустое множество), однако одновременно оно НЕ является подмножеством этих множеств (условия с НЕ тоже истинны)! Похоже, что фирма 1С в платформе 7.7 в запросах с пустыми значениями основательно накосячила.
Проверялось в релизе 27 и формате базы данных DBF.
(65) +67 Дальнейшее тестирование показало, что запрос некорректно работает, когда в условии А является внешней переменной, а Б внешним списком значений:
Условие (А в Б);
Условие (НЕ(А в Б));
тогда при любых числовых и строковых значениях А (на других типах не проверялось) всегда в запросе считается, что А не является подмножеством Б, т.е. первое условие всегда ложно, а второе всегда истинно, даже для случаев:
А=2 и Б={1,2}
А=»2″ и Б={«1″,»2»}
Исключение — А=ПолучитьПустоеЗначение() и А=»», тогда возникает неопределённость: оба условия всегда истинны.
Если же условие на проверку равенства (Б здесь не список значений, а переменная):
Условие (А = Б);
Условие (НЕ(А = Б));
Условие (А <> Б);
тогда запрос работает корректно с учётом типа значения, в том числе считается, что ПолучитьПустоеЗначение()<>»» и «»<>» »
Метод Принадлежит списка значений:
Б.Принадлежит(А)
также работает корректно с учётом типа, в том числе значение «» принадлежит списку, только если в него входит именно это значение (различается «» и » «). Значение ПолучитьПустоеЗначение() никогда не принадлежит списку, так как в него даже невозможно это значение добавить.
Проверялось в релизе 27 и формате базы данных DBF.
(68) В итоге мы публику совсем запутали 😀
(69) Арчибальд ты пишешь, комментируя первый пример :
«Автор по-видимому считает, что при логическом умножении логического значения «Ложь» на что угодно, хоть на стеариновую свечку, должна таки ложь получиться.»
Ты ,помнится, в «лохматые» годы работал на клиппере. (Clipper Summer 87 — вышел 24 года назад).
Ты не помнишь как тогда ,в дремучих 80-х , вычислялись логические выражения ?
Действительно, Если в выражении «А и В» определено ,что А= false ,то вычислялось ли В ?
(69) Сейчас распутаем 🙂
Пост 68 показывает новую ошибку 1С 7.7 для случая запросов с условием вхождения в список значений внешней переменной. Я добавлю это в статью отдельным пунктом.
В пунктах же 9-м и 10-м в условии участвует внутренняя переменная запроса. Я сейчас протестировал (релиз 27, формат базы DBF) простые запросы типа:
Рекв=Справочник.МойСправочник.МойРеквизит;
Условие (Рекв в Б);
и типа:
Рекв=Справочник.МойСправочник.МойРеквизит;
Условие (НЕ(Рекв в Б));
Как я и ожидал, получилось следующее:
Если реквизит справочника МойРеквизит имеет числовой тип и значение 0, то он в запросе считается подмножеством списка Б (условие первого запроса даёт ИСТИНА, а второго — ЛОЖЬ) только тогда, когда в список значений добавлено значение 0.
Если реквизит справочника МойРеквизит имеет строковый тип и значение в виде пустой (пробельной) строки, то он в запросе является подмножеством списка Б только тогда, когда в список добавлена пустая строка той же длины, т.е. проверка производится на точное совпадение.
Таким образом, ещё раз подтверждено, что пустые значения НЕ воспринимаются в запросах как пустые множества.
(70) Все я помню. В Клиппере тоже использовалось, так называемое, сокращенное выполнение логических выражений, и это обстоятельство подчеркивалось в описании. Я говорю о том, что «фичей» я вляется именно сокращенное, а не полное вычисление. А полное вычисление — классическая норма. Программист имеет право пользоваться этим сокращением, но при этом он должен осознавать, что это именно фича.
(72) Ускользнул.
Обновлена статья на сайте. Некоторые пункты протестированы в релизе 27 платформы 1С 7.7. В статье даны дополнительные пояснения и уточнения, добавлены 2 новых пункта с ошибками, обнаруженными в релизе 27.
(72) Ну например в том же С и всех его наследниках сокращенное вычисление логики является именно нормой (не отключаемой 🙂 ). Более того, именно на этом факте основаны приемы типа такой цепочки:
someAct1() && someAct2() && someAct3()
— выполнение последовательно нескольких действий в случае успеха каждого из них; и такая запись много проще и нагляднее лестницы из кучи if-ов. Что же касается квалификации прогера — так в тех языках очень много завязано на side-эффектах, и для прогеров подобные фичи счтиаются базовыми знаниями. Так собственно, почему бы в 8ке не появиться такой же практике?
Что же касается (А>Б И 8) — то как раз для 8ки это корректное выражение, и (8 И А>Б) — также корректное. А дело все в том, что тут числовой тип лЯгко приводится к логическому — по тем же сишным правилам: =0 — ложь, <>0 — истина.
Потому в 8ке можно писать например такое:
Если ТЗ.Количество() Тогда …
(75) При чем здесь С? В нем вообще нет логического типа данных! Еще Бейсик бы вспомнил.
Тут вообще-то ООП обсуждается.
(76) Я написал «С и наследники».
В том что в С++ есть ООП, надеюсь, не сомневаемся?
И, кстати, bool-тип там тоже есть.
Да и обсуждаем вроде не ООП, а логику, что к ООП вообщето перпендикулярно. И да, то что С нет выделенного логического типа никак не убирает из него работу с логикой.
А бейсик (VB?) тут не пойдет — там, как уже говорили выше, полное вычисление операций.
———————
Обрабатывать=0;
Если Док.Вид()=»ПриходнаяНакладная» Тогда
Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя Тогда
Обрабатывать=1;
КонецЕсли;
ИначеЕсли Док.Вид()=»РасходнаяНакладная» Тогда
Если Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Обрабатывать=1;
КонецЕсли;
КонецЕсли;
Если Обрабатывать=1 Тогда
…
КонецЕсли;
———————
А в 1С 8 можно написать:
———————
Если ((Док.Вид()=»ПриходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя))
ИЛИ ((Док.Вид()=»РасходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику))
Тогда
…
КонецЕсли;
———————
Вы действительно считаете второй вариант «неряшливым»? И действительно в 1С 8 всегда создаётеь громаздьё конструкций «Если»?
Показать
если типзначения(?(Док.Вид()=»ПриходнаяНакладная»,?(Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя,1,»Нетути»),?(Док.Вид()=»РасходнаяНакладная»,?(Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику,1,»хренушки»),»ан не попал»)))=1 тогда
КонецЕсли;
(0)
Условие ((Статус<>УчетОказанныхУслуг) И (Статус<>Купленный) И (Статус<>Принятый));
А вот так не проверял?:
Условие (НЕ((Статус=УчетОказанныхУслуг) И (Статус=Купленный) И (Статус=Принятый)));
(79) Так не проверял, поскольку многие косяки в реализации запросов 1С 7.7 фирма 1С допустила как раз в запросах с выражениями с отрицанием.
(79) Как я понимаю, в своём выражении собирались написать ИЛИ, а не И.
(81) Ну да… Недокопипастил 😉
А поводу вашего спора с Арчибальдом:
привычка писать в 8-ке
может привести к ошибке в других языках.
Я стопудово буду «громоздить» Если, но напишу классически:
Если Док.Вид()=»ПриходнаяНакладная» Тогда
Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя
Кстати, именно поэтому мне Си не нравится, с его синтаксическими вы@@@нами.
Вид
!(x>y && y>z)
меня даже чисто эстетически бесит 😉
Но на вкус и цвет…
Все лажа, Автору надо было просто написать…
1. 1С-ные запросы, или как их еще кличут «Черные» запросы, не предназначены для написания сложных запросов, где необходимо брать данные по нескольким «Таблицам» (Регистры, документы, справочники)
2. Если же Программисту, не судьба писать 20-тью «Простыми» запросами, то пиши те на прямых запросах: 1С++ вам в помощь.
3. Плюс не поставил, ибо нечего не ново и все обыденно и логично и без слов автора. Ибо даже при чтении описания языка запросов, там так то ни слова не сказано об возможности написания «Сложных» запросов.
(83) DrZombi,
Вы очень невнимательно читали описание языка запросов, если вообще читали документацию 1С.
Цитирую руководство по описанию встроенного языка 1С:Предприяти 7.7 (Глава 34. Язык Запросов):
===============================================
В объявлении внутренней переменной можно указывать несколько вариантов <ОписанияПеременной>. Все описания должны указывать на один и тот же тип данных (число, строку, справочник или документ). Переменной, указывающей на разные справочники или документы присваивается тип данных «Справочник неопределенного вида» или «Документ неопределенного вида» соответственно.
* Например, можно определить внутреннюю переменную:
Товар = Документ.Перемещение.Товар, Документ.Расходная.Товар;
===============================================
И далее в этой главе идёт огромное количество примеров, когда данные берутся из нескольких таблиц.
Поэтому утверждение, что в 1С 7.7 не нужно писать сложные запросы, — неверно. Другое дело, что в некоторых случаях реализация запросов в платформе 7.7 сделана с ошибками. Но это относится и к очень простым запросам, см. например пункт 14 и 15 статьи.
Статья — так себе, в основном, бояны не принципиальные, коменты — полный отстой.
Мои 5 копеек в коллекцию фич:
Метод списка значений Установить().
СП утверждает:
Установить(<?>,);
Синтаксис:
Установить(<Строка>,<Знач>)
Назначение:
Устанавливает в списке значение с указанным представлением. Если значение с таким представлением уже есть — изменяется значение, если нет — добавляется в конец списка значение с указанным представлением.
Параметры:
<Строка> — строка с символьным представлением устанавливаемого значения;
<Знач> — значение, которое устанавливается в позиции;
Теперь честно не читая дальше ответьте: какой результат даст выполнение метода без второго параметра <Знач>?
По идее, раз значение не указано, для указанного представления будет установлено пустое значение.
Вроде все так — «Устанавливает в списке значение с указанным представлением.»
А теперь честно не читая дальше ответьте: какой результат даст выполнение метода без второго параметра <Знач>, «если значение с таким представлением уже есть»?
0
Интересно, кто-нибудь предвидел такой результат? Только честно?
Т.е., если метод применяется без второго параметра и при этом в списке значение с таким представлением уже есть, то значение с указанным представлением будет не установлено (пустым значением), вместо этого значение с указанным представлением будет удалено(?!) из списка. При этом, было ли у указанного представления установлено ранее какое-либо значение или нет, не имеет значения — значение все равно будет удалено из списка.
(85) BlueWind,
Судя по команде СоздатьОбъект(«ИндексированнаяТаблица»), у Вас используется компонента 1С++. Возможно, именно она нарушает правильную сортировку таблицы значений без индексации. Я сталкивался с тем, что подключение сторонних компонент, может нарушать даже работу того, на что компонента по идее вообще не должна оказывать влияния.
(87)
На 1с++ тоже падало подозрение. Отключил внешние компоненты, заполнение тз выполнил перебором документов, выполнил код:
тз.Сортировать(«Производитель, *Производитель»);
— Результат:
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700305) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1092700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ОАО Калина (700305) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1092700″})
Россия ОАО Калина (700305) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1092700″})
Россия ОАО Калина (700337) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1036700″})
Россия ISN «Марбиофарм» (700306) ({«B»,»0″,»0″,»1110″,»0″,»0″,» 1088700″})
= Элементы 700305 и 700337 не упорядочены. Влияние внешней компоненты, таким образом, исключается.
Сделал выгрузку из SQL в DBF — результат получен точно такой же (без ВК)…
(86) Кошки рулят,
СЗ=СоздатьОбъект(«СписокЗначений»);
СЗ.Установить(«1»);
Сообщить(СЗ.РазмерСписка()); // 1
СЗ.Установить(«1»);
Сообщить(СЗ.РазмерСписка()); // ????
При опущенном параметре <Знач> ожидается, что существующее значение с таким представлением будет удалено из списка. Если это и не документировано, то используется изначально — в стандартных отчетах по бухгалтерии, написанных 1с где-то на границе веков, именно так выполняется удаление значений из расшифровки при выходе из циклов (Расшифровка.Установить(«Субконто»+Номер[1]);). Если при опущенном параметре <Знач> значение удаляется, то при отсутствии в списке значения с таким представлением ожидается, что список останется неизменным. В таком случае, появление в списке пустого значения по строке кода 2 выглядит странным. Интересно, что при явном указании параметра <Знач>, содержащего пустое значение, поведение 1с точно такое же:
Показать
Показать
Не проще ли так, это сразу бросается в глаза и наглядней)) В построение кода нужны еще и мозги. А не только языковые конструкции. Изучайте мат часть.
Если (Док.Вид()=»ПриходнаяНакладная») Или (Док.Вид()=»РасходнаяНакладная») Тогда
Если (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) Или
(Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Обрабатывать=1;
КонецЕсли;
КонецЕсли;
Хорошая статья))) Интересно читать такого рода статьи, несмотря на то, что я ПолныйНуб в семерке)))
Всегда проверяй. Никогда не принимай на веру, то как описан тот или иной функционал в СП или в книжке от 1С 🙂
Лучше всего понимать, что в первозданном виде 1С писалось для ларька по торговле семечками 🙂
И все у вас получится
Исправьте пожалуйста статью.
Получаем:
66699288 Тест
00004369 Тест
66703402 Тест
00004369 Тест
Я при обходах таблиц по таблицам использую:
Показать
Обновлена статья на сайте.
1. Изменён пример в пункте 1.
2. Внесены изменения в пункт 12 в связи с сообщениями BlueWind (85) и TesterMe (93) о проблемах с сортировкой по внутреннему значению элемента справочника.
3. Восстановлена раскраска кода.
в 1с77 использование в выражении докумет.Вид() приводит к скрытому запросу. те тоже является «проблемной» реализацией.
и в описании другой «проблемной» реализации как-то неуместно.
Когда-то давно наткунлся
Справочник.Чтото
Код — текстовый
код заполнен «числами» с ведущими нулями на всю длину кода
В запросе
|Код = Справочник.Чтото.Код;
|Функция СуммаКод=Сумма(Код);
дбф — нормально, скуль — ошибка…
(95) Не понял.
Еще
Метод количествострок() на уменьшение, после сортировки глючит НЕЗАВИСИМО от использования компонент, и глючит всегда.
Обрезает так, как будто не было сортировки.
Список.СортироватьПоПредставлению()
Значения=агрегатный объект.
Ничего не происходит если строка не заполнена, правильно.
Если строка заполнена полностью ее игнорирует и сортирует значения по наименованию. Фокусники, блин. Руки чешутся…