Некоторые ошибки и «проблемные» особенности реализации встроенного языка платформы 1С:Предприятие 7.7




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

98 Comments

  1. kompas-dm

    (0) Просто, грамотным языком и ненавязчиво. Только это 0,01%. Остальное — опыт, практика, тестирование

    Reply
  2. Rustig

    Спасибо за статью! Так держать! 🙂

    Reply
  3. Арчибальд

    (1) Насчет ненавязчиво я бы поспорил.

    Первый пример вообще ни к селу ни к городу.

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

    Автор по-видимому считает, что при логическом умножении логического значения «Ложь» на что угодно, хоть на стеариновую свечку, должна таки ложь получиться.

    Девятый и десятый примеры. Всякому известно, что пустое множество является подмножеством любого множества. А в ЖКК условие вхождения описывается именно в терминах множеств.

    Двенадцатый пример — вообще ни о чем. Понятно же, что сортировка по значению элемента справочника бессмысленна, ибо неповторяема. «Сортировка» будет такой же, как в восьмерочной выборке ДЛЯ КАЖДОГО…

    Тринадцатый пример основан на неявном предположении автора о том, что строка и представление строки — это одно и то же. Если из этого неверного предположения не исходить (а с какой стати?), то текст опять-таки оказывается ни о чем.

    Reply
  4. kompas-dm

    (3) Арчибальд не дремлет…

    С замечаниями согласен. Тема хорошая и нужная для начинающих 1С-ников.

    Reply
  5. Арчибальд

    (4) Заметь, минуса я не поставил, хотя первый пункт меня сильно напряг. 😀 Все же пользы от статьи больше, чем вреда.

    Reply
  6. AleksR

    (3)

    Автор по-видимому считает, что при логическом умножении логического значения «Ложь» на что угодно, хоть на стеариновую свечку, должна таки ложь получиться.

    Программист, когда пишет логическое выражение, ожидает, что его результатом будет либо «Истина», либо «Ложь», а вовсе не «стеариновая свечка» в виде ошибки программы. И он ожидает, что если первый сомножитель «Ложь», то дальше уже проверять незачем. И в 8-й версии 1С:Предприятие это поведение исправлено.

    Девятый и десятый примеры. Всякому известно, что пустое множество является подмножеством любого множества. А в ЖКК условие вхождения описывается именно в терминах множеств.

    Если Вы внимательнее прочтёте 10-й пункт, то увидете, что ситуация неоднозначна (ошибочна): 1С то считает, что пустое значение входит в список, и одновременно (для каких-то условий и функций) не считает.

    Двенадцатый пример — вообще ни о чем. Понятно же, что сортировка по значению элемента справочника бессмысленна, ибо

    неповторяема. «Сортировка» будет такой же, как в восьмерочной выборке ДЛЯ КАЖДОГО…

    В 1С 7.7 сортировка по значению элемента справочника вовсе не бессмысленна. Как я написал в статье: «Таблица значений сортируется по колонке с элементами справочника по их основному представлению».

    Тринадцатый пример основан на неявном предположении автора о том, что строка и представление строки — это одно и то же. Если из этого неверного предположения не исходить (а с какой стати?), то текст опять-таки оказывается ни о чем.

    Тринадцатый пункт о том, какую именно сортировку мы получим в различных случаях. И если Вы считаете, что всё это очевидно, то я удивлён.

    Reply
  7. Арчибальд

    (6)

    И в 8-й версии 1С:Предприятие это поведение исправлено

    Т.е. в восьмерке правильным будет написать

    Если Истина ИЛИ 8 Тогда

    Программист, когда пишет логическое выражение, ожидает, что его результатом будет либо «Истина», либо «Ложь»

    Программист не должен ожидать. Он должен обеспечить, чтобы операнды всех логических операций были логическими. Если он не обеспечил — это его ошибка.

    Если Вы внимательнее прочтёте 10-й пункт, то увидете, что ситуация неоднозначна

    Ситуация как раз однозначна: некорректное написание условия породило некорректную его обработку.

    Сортировка по значению справочника, естественно, происходит по основному представлению. Но если я пишу универсальную обработку, я не знаю каково будет это основное представление в момент запуска, т.е. я не имею права делать об этом какие-либо предположения. Возьму назад только термин «бессмысленна». Вместо него следует читать «некорректна/ошибочна».

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

    Reply
  8. artbear

    Первый пункт четко и точно описан в ЖКК, значит, это не баг, а фича.

    Это известная фича 1С 77.

    Reply
  9. AleksR

    (7)

    Программист не должен ожидать. Он должен обеспечить, чтобы операнды всех логических операций были логическими. Если он не обеспечил — это его ошибка.

    В приведённом в статье примере оба операнда логические:

    Если (Док.Вид()=»ПриходнаяНакладная»)

    И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) Тогда

    Но при этом в 1С 7.7 мы можем наступить на «грабли», если документ Док не имеет реквизита ПризнакНакладной, а в 1С 8 этой проблемы уже нет. И я не пишу, что это ошибка 1С, а пишу, что это особенность обработки сложных логических выражений. Мне непонятно, что Вам не нравится.

    Но если я пишу универсальную обработку, я не знаю каково будет это основное представление в момент запуска, т.е. я не имею права делать об этом какие-либо предположения.

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

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

    В чём некорректность этого условия?

    Условие (НЕ(ВидОтгрузки в СписокВидовОтгрузки));

    Тринадцатый пункт не дает ответа на вопрос, как именно сортируются объекты-строки. Кое-какие частичные наблюдения.

    А я в самом начале написал: «Настоящая статья не претендует на полноту описания и подробный анализ ошибок и «подводных камней» встроенного языка платформы 1С:Предприятие 7.7». Я не теоретик, я описал реальные случаи, с которыми пришлось столкнуться на практике. И это описание (в сокращённом виде, конечно) использовал раньше сам для себя, чтобы не наступать на одни и те же «грабли». И надеюсь, кому-то это тоже пригодится. А в тринадцатом пункте как раз описаны все самые распространённые случаи.

    Reply
  10. Арчибальд

    (9) (Док.ПризнакНакладной = Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) — это операнд неопределенного типа, поскольку сравнивать можно лишь однотипные значения, а значение слева вовсе не обязано иметь тип перечисления, что справа. И если в восьмерке такой финт проходит, то это ошибка восьмерки. Выражение «(1=1) ИЛИ 8» не должно проходить синтаксического контроля. В очередном релизе платформы фирма 1С имеет полное право ошибку исправить…

    ИМХО, большая часть описанного проистекает не из «ошибок и особенностей реализации», а из неряшливости программирования.

    Reply
  11. AleksR

    (10)

    Выражение «(1=1) ИЛИ 8» не должно проходить синтаксического контроля. В очередном релизе платформы фирма 1С имеет полное право ошибку исправить…

    Это Ваше выражение, а не моё. А вот выражение «(1=1) ИЛИ МояПеременная» всегда будет проходить синтаксический контроль и всегда будет давать «Истина» в 1С 8, в отличие от 1С 7, вне зависимости от значения переменной МояПеременная.

    (3)

    Всякому известно, что пустое множество является подмножеством любого множества. А в ЖКК условие вхождения описывается именно в терминах множеств.

    А вот программисты 1С 7.7 не пришли в этом вопросе к полному консенсусу (по крайней мере в релизе 25).

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);

    Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.

    Reply
  12. marsohod

    (10)(11) Господа, Вы спорите по одной простой причине: в языке 1С нет операторов && и ||. Разработчики других языков (например того же PERL) не считают себя самыми умными.

    Бинарное && — логическое И. Если левый аргумент FALSE, то правый не проверяется.

    Бинарное || — логическое ИЛИ. Если левый аргумент TRUE, то правый аргумент не проверяется.
    Reply
  13. awk

    (0) Маленькая справка по первому пункту:

    В 1С 8 не возникнет ошибки не потому, что второй операнд проигнарируется, а потому, что будут сравнивается на равенство типы. Более подробно об этом можно почитать в синтекс-помошнике.

    Reply
  14. AleksR

    (13) Цитата из документации «1С:Предприятие 8.1. Конфигурирование и администрирование», страница 1-251:

    ===========================

    Замечание. При вычислении логического выражения вычисляются только необходимые части выражения. Например, в выражении (Цена > 0) И ПроверкаСуммы(), если Цена <= 0, то функция ПроверкаСуммы() не вызывается.

    ===========================

    Reply
  15. Sergant1

    AleksR хорошая полезная статья.

    Арчибальд критика была не по существу.

    Reply
  16. Арчибальд

    (14)

    При вычислении логического выражения вычисляются только необходимые части выражения. Например, в выражении (Цена > 0) И ПроверкаСуммы(), если Цена <= 0, то функция ПроверкаСуммы() не вызывается.

    … даже и в том случае, когда функция ПроверкаСуммы() имеет результат не логического типа или вообще дает ошибку при вычислении. Неряшливый программист — семерочник из первого примера эту ошибку увидит сразу. Неряшливый программист — восьмерочник может долго еще думать, что он все правильно написал. Грамотный программист озаботится тем, чтобы оба операнда логического выражения были логическими.

    Reply
  17. vkr

    (16) Не стоило бы, наверное, так строго судить… Автору — спасибо за заботу, 1С-ке — минус за глюки! 🙂

    Вы, наверное, тоже могли бы поделиться чем-то аналогичным из своего огромного опыта 1С-программинга…

    З.Ы. Несколько лет назад 1С даже рассылала некий бюллетень ошибок, найденных пользователями,

    правда быстро прекратила — после того, видимо, как его объем вырос за примерно полгода до нескольких сотен строк… 🙂

    Reply
  18. Altair777
    vkr пишет:

    Не стоило бы, наверное, так строго судить… Автору — спасибо за заботу, 1С-ке — минус за глюки!

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

    А вдруг на смену 1С-ке придет что-то лучшее? И тяжело будет этому кодеру писать правильно.

    Reply
  19. AleksR

    (18) В 1С 7.7 приходилось писать:

    ———————

    Обрабатывать=0;

    Если Док.Вид()=»ПриходнаяНакладная» Тогда

    Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя Тогда

    Обрабатывать=1;

    КонецЕсли;

    ИначеЕсли Док.Вид()=»РасходнаяНакладная» Тогда

    Если Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда

    Обрабатывать=1;

    КонецЕсли;

    КонецЕсли;

    Если Обрабатывать=1 Тогда



    КонецЕсли;

    ———————

    А в 1С 8 можно написать:

    ———————

    Если ((Док.Вид()=»ПриходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя))

    ИЛИ ((Док.Вид()=»РасходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику))

    Тогда



    КонецЕсли;

    ———————

    Вы действительно считаете второй вариант «неряшливым»? И действительно в 1С 8 всегда создаётеь громаздьё конструкций «Если»?

    Reply
  20. Арчибальд

    (19) Я просто считаю, что логические операции И и ИЛИ коммутативны. И в семерке это так. Вы же вместе с разработчиками платформы восьмерки это отрицаете.

    Reply
  21. AleksR

    (20) Подход к вычислению логических выражений, реализованный в 1С 8, кроме повышения быстродействия, позволяет создавать более короткий и более «читаемый» код. Пример я привёл выше. Кстати, это вовсе не изобретение 1С 8. В MS Fortran и FoxPro, на которых я работал до 1С, был реализован точно такой же подход. Поэтому для меня «лишние» вычисления в логическом выражении оказались в 1С 7 неприятным сюрпризом.

    Reply
  22. Altair777

    (19) не надо путать громоздкость кода с неряшливым подходом к вычисляемым условиям

    Reply
  23. Арчибальд

    (21) Да, код получается более коротким. Но не более читаемым — наша дискуссия тому доказательство.

    Этот способ сокращения записи имеет право на существование, однако ж при чтении надо понимать, что краткость достигается за счет правильного понимания ненаписанного. А именно: в логических выражениях в восьмерке (и ряде других языков) отключен (частично) контроль корректности вычислений. Это фича (особенность реализации) таких языков, специально упоминаемая в описании языка. Отсутствие такого упоминания автоматически означает, что типы операндов контролируются путем вычисления.

    На этапе составлении алгоритма я считаю некорректным использование особенностей реализации языка — тогда из «программиста» превращаешься в «программиста 1С8» или «программиста ФоксПро». Ну, а в первом примере «программист» и «программист 1С7.7» совпадают.

    Reply
  24. Franchiser

    Я тоже встречал ошибки: 1с по-разному работает под sql и под dbf:

    — На скуле некорреткно работают запросы когда в них выбираются через точку реквизиты какого-либо справочника, причем в запросе обращение к этому справочнику стоит 2 и более раз.

    — Почему то по оборотным счетам в базе на скуле хранятся в том числе и остатки.

    Reply
  25. gaglo

    (23) Дискуссия идет «вот уже пятые сутки», и я не вытерпел…

    Арчибальд пишет:

    В логических выражениях в восьмерке (и ряде других языков) отключен (частично) контроль корректности вычислений.

    Это фича (особенность реализации) таких языков, специально упоминаемая в описании языка.

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

    На этапе составлении алгоритма я считаю некорректным использование особенностей реализации языка

    Считаю, что спор пошел уже совсем ни о чем не о том, поскольку:

    — «ряд других языков» есть на деле большинство языков; ИМХО неполное вычисление логического выражения применяется в 1С8, Фортране, С и С++, полное в 1С7 и Visual Basic, счет 4:2;

    — не «отключен контроль корректности вычислений», а отсутствует строгая типизация и широко распространено приведение типов, в том числе и неявное, из-за чего о контроле корректности вычислений без выполнения этих самых вычислений лучше не вспоминать;

    — упоминание о таком способе вычисления логических выражений как о фиче в отношении языка 1С8 имеется, что было показано в посте 14;

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

    — и, кстати, на коммутативность логических операций это никоим боком не посягает, а выражение «(1=1) ИЛИ 8» синтаксически абсолютно верно, и только семантически с ним (возможно) что-то не так.

    Reply
  26. nafa

    (25)

    — «ряд других языков» есть на деле большинство языков; ИМХО неполное вычисление логического выражения применяется в 1С8, Фортране, С и С++, полное в 1С7 и Visual Basic, счет 4:2;

    Более правильно сказать, что в ряде компиляторов (именно компиляторов, а не языков) — MS VC++, C++ Builder и т.п. есть настройка (включаемая пользователем), которая позволяет вычислять логические выражения неполностью.

    Так как вычисление полностью нередко бывает необходимо на этапе отладки программ, чтобы максимально быстро выявить все ошибки.

    Reply
  27. Ёпрст

    А вот когда автор узнает про * в параметрах сортировки, то не будет писать бреда типа этого:

    Табл.Сортировать(«Клиент,КлиентКод»);

    Reply
  28. Ёпрст

    +27 и тем более, не нужно лепить новую колонку для сортировки.

    Reply
  29. Dolly_EV

    Как всегда, в таких статьях — комменты рулят!)

    Обход проблемы в п. 4:

    «Условие (ВыбКлиент.Принадлежит(Клиент)=1);»

    Reply
  30. Altair777
    gaglo пишет:

    — «ряд других языков» есть на деле большинство языков; ИМХО неполное вычисление логического выражения применяется в 1С8, Фортране, С и С++, полное в 1С7 и Visual Basic, счет 4:2;

    1. При чем тут счет?!

    2. Вы всего о 6 языках слышали? 😀

    Reply
  31. AleksR
    Dolly_EV пишет:

    Обход проблемы в п. 4:

    «Условие (ВыбКлиент.Принадлежит(Клиент)=1);»

    Так нельзя. Общее правило для фильтров: если он не установлен (список значений ВыбКлиент пустой), то условие должно быть истинно.

    Reply
  32. AleksR

    (27) Цель — отсортировать таблицу значений по наименованию, но так чтобы не оказались строки с разными элементами справочника, но одинаковыми наименованиями вперемешку. А при сортировке по внутреннему значению получим рядом все строки, относящиеся к одному элементу справочника, но упорядочивания по элементам вообще никакого не будет.

    Reply
  33. Ёпрст

    (32) Ё.. как дети.

    Табл.Сортировать(«Клиент+,Клиент*»);

    Reply
  34. AleksR

    (33) Согласен. Так действительно лучше.

    Это, на мой взгляд, первое дельное замечание по содержанию статьи.

    Reply
  35. Ёпрст

    >>>3. Ошибка запроса по месяцам

    Брехня.

    Reply
  36. Ёпрст

    +35 есть ВСЁ.

    Reply
  37. Ёпрст

    >>>4.

    Аналогично — всё работает.

    ЗЫ: максимум, на SQL базе не всегда работает — а именно, если в списке 1 элемент , то фильтр игнорируется.

    Reply
  38. Ёпрст

    +37

    >>7.

    Тоже бред. Функция всегда рассчитывается верно, если статус — измерение регистра.

    Мот ты условия на реквизит регистра накладываешь ?

    :))))))))))

    Единственное — в запросе используется уп

    Reply
  39. Altair777

    Ёпрст, где ты раньше был? 🙂

    Reply
  40. AleksR
    Ёпрст пишет:

    >>>3. Ошибка запроса по месяцам

    Брехня.

    Отсутствие ошибки в непонятно каком релизе платформы в непонятно каком формате базы вовсе не означает, что её не было в 17-м релизе DBF-базы. Не исключено также, что ошибка может наблюдаться при дополнительных условиях, которые были в реальном запросе.

    Reply
  41. Ёпрст

    (40) з@ебись .. Мот тебе еще и все ошибки всех древних релизов перечислить ?

    Их есть у меня.

    Reply
  42. Altair777

    (40)

    AleksR пишет:

    что её не было в 17-м релизе DBF-базы

    а в в 25 или 27 релизе она есть?

    Reply
  43. AleksR

    (38) Это чего — теоретические рассуждения? Логических ошибок в этих запросах нет — они есть в реализации на платформе 1С 7.7 и конкретно наблюдались в 25 релизе на SQL-базе.

    пустое значение всегда принадлежит любому множеству

    А об этом я уже писал:

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);

    Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.

    Это не в теории, а в конкретной практике.

    Reply
  44. Altair777

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

    (43)

    AleksR пишет:

    Это не в теории, а в конкретной практике

    Если практика конкретная — проблема 1-5 осталась в 25 релизе? а в 27?

    P.S. Очень хочется снести эту публикацию — по-моему, от нее вреда больше чем пользы.

    Жалко только что комменты Арчибальда и Ёпрста погибнут вместе с ней.

    Reply
  45. AleksR

    (40) В самом начале статьи я написал, какая проблема обнаружена в каком релизе и в каком формате базы, и предложил проверить всем желающим актуальность для последнего релиза.

    Reply
  46. Ёпрст
    А об этом я уже писал:

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (НЕ(КодОперации в СписокКодовОпераций));

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);

    Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае.

    Это не в теории, а в конкретной практике.

    Тебе еще раз говорят — пустое значение является элементом любого множества.

    Да и, открой профайлер наконец.

    Reply
  47. AleksR

    (45) А тебе ещё раз говорят: в конкретной практике «функция для пустого значения КодОперации не выполняется ни в первом, ни во втором случае».

    Reply
  48. Altair777

    (46) Мало кто видит для какого она релиза, это же надо каджый раз вверх подниматься

    Reply
  49. AleksR

    (48) Я внесу уточнения в статью.

    Reply
  50. alexk-is

    Программный код в тексте публикации можно было раскрасить более простым способом 🙂

    Reply
  51. Арчибальд

    (50) Какое ожесточение? Ни я, ни Ёпрст (основные критики) минусом к статье не отметились, продемонстрировав тем самым свою толерантность. А вот автору следовало бы часть высказанных замечаний внести в текст статьи — не каждый полезет в обсуждение, и останется в результате весьма далек от истины.

    Reply
  52. AleksR

    (52)

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

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

    Reply
  53. AleksR

    (38)

    пустое значение всегда принадлежит любому множеству

    Это неверное утверждение. В математике правильно так: пустое множество является подмножеством любого множество.

    Причём пустое множество — это множество, не содержащее ни одного элемента.

    Таким образом, элемент со значением 0 не принадлежит множеству {1; 2; 3}. Полный аналог пустого множество — это NULL в 1С 8.

    Reply
  54. AleksR

    (51) А я и раскрашивал с помощью Вашей обработки «Разукрашка». Очень удобно. Спасибо ещё раз! Просто я результат раскраски вставлял в статью в Word. А уже всю статью из Word через буфер обмена копировал в поле описания публикации.

    Reply
  55. alexk-is

    (55) Вот я и смотрю, что код HTML страшнее страшного.

    Reply
  56. Арчибальд

    (54) ЖКК, стр. 823:

    Оператор языка запросов «Условие (А в Б);» говорит о том, что условие истинно, когда значение А является подмножеством значения Б.

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

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

    Пример: ПолучитьПустоеЗначение() принадлежит {1; 2; 3}, а ПолучитьПустоеЗначение(«Число») — не принадлежит. ПолучитьПустоеЗначение() — это полный аналог NULL в 1С 8…

    Reply
  57. AleksR

    (57) В пункте 9 статьи, о котором и идёт спор, на вхождение в список проверяется КодОперации, являющийся реквизитом регистра. И он имеет вполне определённый тип. И проверяться на вхождение будет не абстрактное ПолучитьПустоеЗначение(), а вполне конкретный » » (пробел), если КодОперации имеет тип строки длиной 1.

    Reply
  58. Арчибальд

    (58) А вот в этом конкретном месте ляп имеется.

    В ЖКК имеется указание на то, что для строк ПустоеЗначение() работает как ПустаяСтрока(). На мой взгляд, эта фича весьма вредна. Разумным было бы результатом функции ПустоеЗначение(» «) иметь 0. Хотя бы потому, что СтрДлина() прекрасно считает пробелы.

    Скуль, насколько мне известно (не уверен), пробельную строку пустым значением не считает.

    Reply
  59. AleksR

    (59) В чём ляп? Как вы сами согласились, 1С считает пробельную строку тоже пустым значением. Поэтому в статье я и употреблял этот термин, как наиболее общий. Не важно, какой тип у реквизита КодОперации. Но для каждого типа есть своё пустое значение. И это не NULL в данном примере.

    Reply
  60. Арчибальд

    (60)

    Но для каждого типа есть своё пустое значение.

    В данном случае, не одно пустое значение.

    ПустоеЗначение(» «) = 1

    но

    » » <> ПолучитьПустоеЗначение(«Строка»);

    Вот я и считаю, что здесь 1С допустила ляп.

    Reply
  61. AleksR

    Я согласен, что 1С достаточно вольно обращается с пробелами. Но речь-то идёт о другом. Согласитесь всё же, что Ваше замечание:

    Девятый и десятый примеры. Всякому известно, что пустое множество является подмножеством любого множества. А в ЖКК условие вхождения описывается именно в терминах множеств.

    некорректно по сути, так как в 9-м и 10-м примерах нет пустого множества, а есть пустые значения и это не одно и то же.

    Reply
  62. Арчибальд

    (62) Потому я в 57 посте и процитировал ЖКК: «Значение А является подмножеством значения Б». Очень коряво. Когда Б — СписокЗначений, напрашивается вывод, что и А должно как-то преобразовываться в список. И еще вопрос, если А — пустое значение, будет ли оно преобразовано в пустой список, либо в список, состоящий из одного пустого значения. К тому же списки длины 1 вообще ведут себя в запросах коряво.

    Reply
  63. AleksR

    (63) Если и преобразуется, то в список из одного пустого значения. Как я уже дважды писал:

    Функция ПрихДолг = Приход(ДолгПокуп) Когда (КодОперации в СписокКодовОпераций);

    Если пустое значение не входит в список СписокКодовОпераций, то функция для пустого значения КодОперации не выполняется. И это, на мой взгляд, не ошибка 1С. А ошибка, когда при условии «НЕ(КодОперации в СписокКодовОпераций)» тоже не выполняется. И в ряде других запросов, которые я приводил, проблемы происходят при условии отрицания. В 10-м пункте я описал реальную ситуацию, с которой столкнулся, когда не выполняются лишь некоторые функции и лишь при некоторых условиях. Когда же отрицания нет, то с такими проблемами я не сталкивался.

    Reply
  64. Арчибальд

    Не поленился проверить:

    Б = СоздатьОбъект(«СписокЗначений»);

    Б.ДобавитьЗначение(1);

    Б.ДобавитьЗначение(2);

    Б.ДобавитьЗначение(0);

    А = 0;

    Условие (А в Б) = Ложь

    А = ПолучитьПустоеЗначение(«Число»);

    Условие (А в Б) = Ложь

    А = ПолучитьПустоеЗначение();

    Условие (А в Б) = Истина

    Вот так как то… Для ДБФ. А в скуле — не так…

    Reply
  65. AleksR

    (65) А как именно Вы проверяли Условие (А в Б)? Я проверил то же самое с помощью метода Принадлежит():

    Б.Принадлежит(А)

    и получил противоположный результат:

    значение принадлежит данном списку в первых двух случаях (когда А=0 и А=ПолучитьПустоеЗначение(«Число»)) и НЕ принадлежит в последнем (когда А=ПолучитьПустоеЗначение()).

    Если же в списке нет элемента со значением 0, тогда все три вышеуказанные значения НЕ принадлежат списку.

    Из описания встроенного языка системы 1С:Предприятие 7.7:

    «Метод Принадлежит проверяет вхождение в список значений заданного значения. Другими словами, оператор Список.Принадлежит(ВыбДок) проверяет, является ли значение ВыбДок подмножеством списка значений Список.»

    Таким образом, ПолучитьПустоеЗначение() тоже не является пустым множеством. Согласно документации, это пустое значение неопределённого типа.

    Проверялось в релизе 27 и формате базы данных DBF.

    Reply
  66. AleksR

    (65) +66 Сейчас потестил как запрос работает для двух вариантов условий:

    Условие (А в Б);

    Условие (НЕ(А в Б));

    для двух вариантов списка значений Б:

    {1; 2; 0}

    {1; 2}

    и для трёх вариантов значений А:

    0

    ПолучитьПустоеЗначение(«Число»)

    ПолучитьПустоеЗначение()

    Для значений 0 и ПолучитьПустоеЗначение(«Число») все результаты одинаковы, что подтверждает эквивалентность этих значений. Дальше для краткости буду писать только про значение 0.

    Из результатов запросов следует, что с точки зрения реализации запроса значение 0 не является подмножеством множества {1; 2}, что, на мой взгляд, логично. Однако, как Вы и писали, оно также не является подмножеством множества {1; 2; 0}, что уже совсем нелогично. Для значения ПолучитьПустоеЗначение() получается вообще полный бред: условие истинно для всех четырёх вариантов, т.е. ПолучитьПустоеЗначение() является подмножеством обоих множеств (это можно было бы трактовать как то, что ПолучитьПустоеЗначение() — это пустое множество), однако одновременно оно НЕ является подмножеством этих множеств (условия с НЕ тоже истинны)! Похоже, что фирма 1С в платформе 7.7 в запросах с пустыми значениями основательно накосячила.

    Проверялось в релизе 27 и формате базы данных DBF.

    Reply
  67. AleksR

    (65) +67 Дальнейшее тестирование показало, что запрос некорректно работает, когда в условии А является внешней переменной, а Б внешним списком значений:

    Условие (А в Б);

    Условие (НЕ(А в Б));

    тогда при любых числовых и строковых значениях А (на других типах не проверялось) всегда в запросе считается, что А не является подмножеством Б, т.е. первое условие всегда ложно, а второе всегда истинно, даже для случаев:

    А=2 и Б={1,2}

    А=»2″ и Б={«1″,»2»}

    Исключение — А=ПолучитьПустоеЗначение() и А=»», тогда возникает неопределённость: оба условия всегда истинны.

    Если же условие на проверку равенства (Б здесь не список значений, а переменная):

    Условие (А = Б);

    Условие (НЕ(А = Б));

    Условие (А <> Б);

    тогда запрос работает корректно с учётом типа значения, в том числе считается, что ПолучитьПустоеЗначение()<>»» и «»<>» »

    Метод Принадлежит списка значений:

    Б.Принадлежит(А)

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

    Проверялось в релизе 27 и формате базы данных DBF.

    Reply
  68. Арчибальд

    (68) В итоге мы публику совсем запутали 😀

    Reply
  69. Ish_2

    (69) Арчибальд ты пишешь, комментируя первый пример :

    «Автор по-видимому считает, что при логическом умножении логического значения «Ложь» на что угодно, хоть на стеариновую свечку, должна таки ложь получиться.»

    Ты ,помнится, в «лохматые» годы работал на клиппере. (Clipper Summer 87 — вышел 24 года назад).

    Ты не помнишь как тогда ,в дремучих 80-х , вычислялись логические выражения ?

    Действительно, Если в выражении «А и В» определено ,что А= false ,то вычислялось ли В ?

    Reply
  70. AleksR

    (69) Сейчас распутаем 🙂

    Пост 68 показывает новую ошибку 1С 7.7 для случая запросов с условием вхождения в список значений внешней переменной. Я добавлю это в статью отдельным пунктом.

    В пунктах же 9-м и 10-м в условии участвует внутренняя переменная запроса. Я сейчас протестировал (релиз 27, формат базы DBF) простые запросы типа:

    Рекв=Справочник.МойСправочник.МойРеквизит;

    Условие (Рекв в Б);

    и типа:

    Рекв=Справочник.МойСправочник.МойРеквизит;

    Условие (НЕ(Рекв в Б));

    Как я и ожидал, получилось следующее:

    Если реквизит справочника МойРеквизит имеет числовой тип и значение 0, то он в запросе считается подмножеством списка Б (условие первого запроса даёт ИСТИНА, а второго — ЛОЖЬ) только тогда, когда в список значений добавлено значение 0.

    Если реквизит справочника МойРеквизит имеет строковый тип и значение в виде пустой (пробельной) строки, то он в запросе является подмножеством списка Б только тогда, когда в список добавлена пустая строка той же длины, т.е. проверка производится на точное совпадение.

    Таким образом, ещё раз подтверждено, что пустые значения НЕ воспринимаются в запросах как пустые множества.

    Reply
  71. Арчибальд

    (70) Все я помню. В Клиппере тоже использовалось, так называемое, сокращенное выполнение логических выражений, и это обстоятельство подчеркивалось в описании. Я говорю о том, что «фичей» я вляется именно сокращенное, а не полное вычисление. А полное вычисление — классическая норма. Программист имеет право пользоваться этим сокращением, но при этом он должен осознавать, что это именно фича.

    Reply
  72. Ish_2

    (72) Ускользнул.

    Reply
  73. AleksR

    Обновлена статья на сайте. Некоторые пункты протестированы в релизе 27 платформы 1С 7.7. В статье даны дополнительные пояснения и уточнения, добавлены 2 новых пункта с ошибками, обнаруженными в релизе 27.

    Reply
  74. alexqc

    (72) Ну например в том же С и всех его наследниках сокращенное вычисление логики является именно нормой (не отключаемой 🙂 ). Более того, именно на этом факте основаны приемы типа такой цепочки:

    someAct1() && someAct2() && someAct3()

    — выполнение последовательно нескольких действий в случае успеха каждого из них; и такая запись много проще и нагляднее лестницы из кучи if-ов. Что же касается квалификации прогера — так в тех языках очень много завязано на side-эффектах, и для прогеров подобные фичи счтиаются базовыми знаниями. Так собственно, почему бы в 8ке не появиться такой же практике?

    Что же касается (А>Б И 8) — то как раз для 8ки это корректное выражение, и (8 И А>Б) — также корректное. А дело все в том, что тут числовой тип лЯгко приводится к логическому — по тем же сишным правилам: =0 — ложь, <>0 — истина.

    Потому в 8ке можно писать например такое:

    Если ТЗ.Количество() Тогда …

    Reply
  75. Арчибальд

    (75) При чем здесь С? В нем вообще нет логического типа данных! Еще Бейсик бы вспомнил.

    Тут вообще-то ООП обсуждается.

    Reply
  76. alexqc

    (76) Я написал «С и наследники».

    В том что в С++ есть ООП, надеюсь, не сомневаемся?

    И, кстати, bool-тип там тоже есть.

    Да и обсуждаем вроде не ООП, а логику, что к ООП вообщето перпендикулярно. И да, то что С нет выделенного логического типа никак не убирает из него работу с логикой.

    А бейсик (VB?) тут не пойдет — там, как уже говорили выше, полное вычисление операций.

    Reply
  77. waol
    AleksR пишет:

    (18) В 1С 7.7 приходилось писать:

    ———————

    Обрабатывать=0;

    Если Док.Вид()=»ПриходнаяНакладная» Тогда

    Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя Тогда

    Обрабатывать=1;

    КонецЕсли;

    ИначеЕсли Док.Вид()=»РасходнаяНакладная» Тогда

    Если Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда

    Обрабатывать=1;

    КонецЕсли;

    КонецЕсли;

    Если Обрабатывать=1 Тогда

    КонецЕсли;

    ———————

    А в 1С 8 можно написать:

    ———————

    Если ((Док.Вид()=»ПриходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя))

    ИЛИ ((Док.Вид()=»РасходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику))

    Тогда

    КонецЕсли;

    ———————

    Вы действительно считаете второй вариант «неряшливым»? И действительно в 1С 8 всегда создаётеь громаздьё конструкций «Если»?

    Показать

    если типзначения(?(Док.Вид()=»ПриходнаяНакладная»,?(Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя,1,»Нетути»),?(Док.Вид()=»РасходнаяНакладная»,?(Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику,1,»хренушки»),»ан не попал»)))=1 тогда

    КонецЕсли;

    Reply
  78. Abadonna

    (0)

    или с проверками на неравенство значений и логическим оператором И, например:

    Условие ((Статус<>УчетОказанныхУслуг) И (Статус<>Купленный) И (Статус<>Принятый));

    А вот так не проверял?:

    Условие (НЕ((Статус=УчетОказанныхУслуг) И (Статус=Купленный) И (Статус=Принятый)));

    Reply
  79. AleksR

    (79) Так не проверял, поскольку многие косяки в реализации запросов 1С 7.7 фирма 1С допустила как раз в запросах с выражениями с отрицанием.

    Reply
  80. AleksR

    (79) Как я понимаю, в своём выражении собирались написать ИЛИ, а не И.

    Reply
  81. Abadonna

    (81) Ну да… Недокопипастил 😉

    А поводу вашего спора с Арчибальдом:

    привычка писать в 8-ке

    Если ((Док.Вид()=»ПриходнаяНакладная») И (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя))

    может привести к ошибке в других языках.

    Я стопудово буду «громоздить» Если, но напишу классически:

    Если Док.Вид()=»ПриходнаяНакладная» Тогда

    Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя

    Кстати, именно поэтому мне Си не нравится, с его синтаксическими вы@@@нами.

    Вид

    !(x>y && y>z)

    меня даже чисто эстетически бесит 😉

    Но на вкус и цвет…

    Reply
  82. DrZombi

    Все лажа, Автору надо было просто написать…

    1. 1С-ные запросы, или как их еще кличут «Черные» запросы, не предназначены для написания сложных запросов, где необходимо брать данные по нескольким «Таблицам» (Регистры, документы, справочники)

    2. Если же Программисту, не судьба писать 20-тью «Простыми» запросами, то пиши те на прямых запросах: 1С++ вам в помощь.

    3. Плюс не поставил, ибо нечего не ново и все обыденно и логично и без слов автора. Ибо даже при чтении описания языка запросов, там так то ни слова не сказано об возможности написания «Сложных» запросов.

    Reply
  83. AleksR

    (83) DrZombi,

    Ибо даже при чтении описания языка запросов, там так то ни слова не сказано об возможности написания «Сложных» запросов.

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

    Цитирую руководство по описанию встроенного языка 1С:Предприяти 7.7 (Глава 34. Язык Запросов):

    ===============================================

    В объявлении внутренней переменной можно указывать несколько вариан­тов <ОписанияПеременной>. Все описания должны указывать на один и тот же тип данных (число, строку, справочник или документ). Переменной, указы­вающей на разные справочники или документы присваивается тип данных «Справочник неопределенного вида» или «Документ неопределенного вида» соответственно.

    * Например, можно определить внутреннюю переменную:

    Товар = Документ.Перемещение.Товар, Документ.Расходная.Товар;

    ===============================================

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

    Поэтому утверждение, что в 1С 7.7 не нужно писать сложные запросы, — неверно. Другое дело, что в некоторых случаях реализация запросов в платформе 7.7 сделана с ошибками. Но это относится и к очень простым запросам, см. например пункт 14 и 15 статьи.

    Reply
  84. BlueWind
    Reply
  85. Кошки рулят

    Статья — так себе, в основном, бояны не принципиальные, коменты — полный отстой.

    Мои 5 копеек в коллекцию фич:

    Метод списка значений Установить().

    СП утверждает:

    Установить(<?>,);

    Синтаксис:

    Установить(<Строка>,<Знач>)

    Назначение:

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

    Параметры:

    <Строка> — строка с символьным представлением устанавливаемого значения;

    <Знач> — значение, которое устанавливается в позиции;

    Теперь честно не читая дальше ответьте: какой результат даст выполнение метода без второго параметра <Знач>?

     СЗ=СоздатьОбъект(«СписокЗначений»);
    СЗ.Установить(«1»);   

    По идее, раз значение не указано, для указанного представления будет установлено пустое значение.

     Сообщить(СЗ.РазмерСписка());  // 1 

    Вроде все так — «Устанавливает в списке значение с указанным представлением.»

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

     СЗ=СоздатьОбъект(«СписокЗначений»);
    СЗ.Установить(«1»);
    Сообщить(СЗ.РазмерСписка());  // 1
    СЗ.Установить(«1»);
    Сообщить(СЗ.РазмерСписка());  // ????
    

    0

    Интересно, кто-нибудь предвидел такой результат? Только честно?

    Т.е., если метод применяется без второго параметра и при этом в списке значение с таким представлением уже есть, то значение с указанным представлением будет не установлено (пустым значением), вместо этого значение с указанным представлением будет удалено(?!) из списка. При этом, было ли у указанного представления установлено ранее какое-либо значение или нет, не имеет значения — значение все равно будет удалено из списка.

    Reply
  86. AleksR

    (85) BlueWind,

    Судя по команде СоздатьОбъект(«ИндексированнаяТаблица»), у Вас используется компонента 1С++. Возможно, именно она нарушает правильную сортировку таблицы значений без индексации. Я сталкивался с тем, что подключение сторонних компонент, может нарушать даже работу того, на что компонента по идее вообще не должна оказывать влияния.

    Reply
  87. BlueWind

    (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 — результат получен точно такой же (без ВК)…

    Reply
  88. BlueWind

    (86) Кошки рулят,


    СЗ=СоздатьОбъект(«СписокЗначений»);

    СЗ.Установить(«1»);

    Сообщить(СЗ.РазмерСписка()); // 1

    СЗ.Установить(«1»);

    Сообщить(СЗ.РазмерСписка()); // ????

    При опущенном параметре <Знач> ожидается, что существующее значение с таким представлением будет удалено из списка. Если это и не документировано, то используется изначально — в стандартных отчетах по бухгалтерии, написанных 1с где-то на границе веков, именно так выполняется удаление значений из расшифровки при выходе из циклов (Расшифровка.Установить(«Субконто»+Номер[1]);). Если при опущенном параметре <Знач> значение удаляется, то при отсутствии в списке значения с таким представлением ожидается, что список останется неизменным. В таком случае, появление в списке пустого значения по строке кода 2 выглядит странным. Интересно, что при явном указании параметра <Знач>, содержащего пустое значение, поведение 1с точно такое же:

    СЗ=СоздатьОбъект(«СписокЗначений»);
    СЗ.Установить(«1″, ПолучитьПустоеЗначение());
    Сообщить(СЗ.РазмерСписка());  // 1
    Если сз.РазмерСписка() <> 0 Тогда
    Сообщить(?(сз.ПолучитьЗначение(1) = ПолучитьПустоеЗначение(),»Пустое»,»Не пустое»)); //Пустое
    КонецЕсли;
    СЗ.Установить(«1», ПолучитьПустоеЗначение());
    Сообщить(СЗ.РазмерСписка());  // 0
    

    Показать

    Reply
  89. Однако в 1С 7 приходится в таком случае создавать более громоздкую и менее наглядную конструкцию:
    
    Обрабатывать=0;
    Если      Док.Вид()=»ПриходнаяНакладная» Тогда
    Если Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя Тогда
    Обрабатывать=1;
    КонецЕсли;
    ИначеЕсли Док.Вид()=»РасходнаяНакладная» Тогда
    Если Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
    Обрабатывать=1;
    КонецЕсли;
    КонецЕсли;
    Если Обрабатывать=1 Тогда

    Показать

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

    Если (Док.Вид()=»ПриходнаяНакладная») Или (Док.Вид()=»РасходнаяНакладная») Тогда

    Если (Док.ПризнакНакладной=Перечисление.ПризнПрихНакл.ВозвратОтПокупателя) Или

    (Док.ПризнакНакладной=Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда

    Обрабатывать=1;

    КонецЕсли;

    КонецЕсли;

    Reply
  90. Bukaska

    Хорошая статья))) Интересно читать такого рода статьи, несмотря на то, что я ПолныйНуб в семерке)))

    Reply
  91. DrZombi

    Всегда проверяй. Никогда не принимай на веру, то как описан тот или иной функционал в СП или в книжке от 1С 🙂

    Лучше всего понимать, что в первозданном виде 1С писалось для ларька по торговле семечками 🙂

    И все у вас получится

    Reply
  92. TesterMe

    Исправьте пожалуйста статью.

    Табл.Сортировать(«Клиент+,Клиент*»); // работает тоже неверно

    Получаем:

    66699288 Тест

    00004369 Тест

    66703402 Тест

    00004369 Тест

    Табл.Сортировать(«Клиент,КлиентКод»); // сортировать только так

    Я при обходах таблиц по таблицам использую:

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

    Показать

    Reply
  93. AleksR

    Обновлена статья на сайте.

    1. Изменён пример в пункте 1.

    2. Внесены изменения в пункт 12 в связи с сообщениями BlueWind (85) и TesterMe (93) о проблемах с сортировкой по внутреннему значению элемента справочника.

    3. Восстановлена раскраска кода.

    Reply
  94. МихаилМ

    в 1с77 использование в выражении докумет.Вид() приводит к скрытому запросу. те тоже является «проблемной» реализацией.

    и в описании другой «проблемной» реализации как-то неуместно.

    Reply
  95. CheBurator

    Когда-то давно наткунлся

    Справочник.Чтото

    Код — текстовый

    код заполнен «числами» с ведущими нулями на всю длину кода

    В запросе

    |Код = Справочник.Чтото.Код;

    |Функция СуммаКод=Сумма(Код);

    дбф — нормально, скуль — ошибка…

    Reply
  96. AleksR

    (95) Не понял.

    Reply
  97. CheBurator

    Еще

    Метод количествострок() на уменьшение, после сортировки глючит НЕЗАВИСИМО от использования компонент, и глючит всегда.

    Обрезает так, как будто не было сортировки.

    Reply
  98. recop

    Список.СортироватьПоПредставлению()

    Значения=агрегатный объект.

    Ничего не происходит если строка не заполнена, правильно.

    Если строка заполнена полностью ее игнорирует и сортирует значения по наименованию. Фокусники, блин. Руки чешутся…

    Reply

Leave a Comment

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