Выразить число как строку и дату как строку в запросе




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

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

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

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

65 Comments

  1. spetzpozh

    Моя обычная реакция на публикации Маэстро — посмотрел, почесал репу, плюсанул и пошел дальше )))

    Reply ↓
  2. ololoanonim

    Выглядит весьма круто =)

    Reply ↓
  3. GROOVY

    Фундаментально выглядит. Но нафига? Никогда не понимал, зачем это нужно.

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

    Reply ↓
  4. ildarovich
    Reply ↓
  5. break

    а без значащихся нулей перед числами можно соорудить?

    Reply ↓
  6. ildarovich

    (5) break, можно, если интерес не праздный. Приведите пример практической задачи — сделаю.

    Reply ↓
  7. chmv

    А попроще. Может быть когда-нибудь и 1с это реализует

    Reply ↓
  8. gaglo

    Большое спасибо за идею использования функции СЕКУНДА для получения остатка от деления. (Кажется мне, что простая проверка четности и другой кратности в запросе надобна чаще, чем перевод числа в строку.)

    Reply ↓
  9. chmv

    8 Как раз Вы не правы, чаще перевод даты в строку

    Reply ↓
  10. Поручик

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

    Reply ↓
  11. monkbest

    Я правильно понимаю, что строки полученные Вашим методом, потом можно складывать?

    Потому что такой вот запрос вернет число как строку неограниченной длины

    ВЫБРАТЬ
    ВзаиморасчетыССотрудниками.СуммаВзаиморасчетов,
    ПРЕДСТАВЛЕНИЕ(ВзаиморасчетыССотрудниками.СуммаВзаиморасчетов) КАК СуммаВзаиморасчетов1
    ИЗ
    РегистрНакопления.ВзаиморасчетыССотрудниками КАК ВзаиморасчетыССотрудниками
    ГДЕ
    ВзаиморасчетыССотрудниками.Сотрудник = &Сотрудник
    Reply ↓
  12. ildarovich

    (11) monkbest, да, можно складывать.

    В вашем запросе «представление» это строка, которая формируется не в СУБД, а платформой в процессе постобработки запроса. Также как «итоги», например. Поэтому «представление» вы никак в самом запросе далее использовать не можете.

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

    Reply ↓
  13. sanfoto

    (12)

    В вашем запросе «представление» это строка, которая формируется не в СУБД, а платформой в процессе постобработки запроса.

    так то в принципе и 1С запросы — не чисто SQL запросы, а реляционно-подобные «объектные запросы к ВИРТУАЛЬНОЙ объектной модели»…

    т.е. в процессе выполнения такого «объектного запроса» — генирится много дополнительного SQL кода для получения этих объектов..

    К чему я это пишу — к тому что повальное увлечение переноса абсолютно всего кода в «1С запрос» — совсем не всегда оправдано на платформе «1С». На практике часто бывает быстрей отрабатывает(и пишется..) код с циклами с использованием 1С объектов «ТаблицаЗначений» и т.д.

    Reply ↓
  14. ildarovich

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

    Reply ↓
  15. alex_4x

    Reply ↓
  16. ildarovich

    (15) alex_4x, картинку сами рисовали (редактировали) или взяли откуда?

    Reply ↓
  17. alex_4x

    (16) Это Дилберт! Они очень наслышаны о нашей 1С 🙂

    Reply ↓
  18. Serj1C

    Связываться с датами для усечения дробной части? не накладно?

    Может попробовать функцию Выразить(&Число-0.49 как Число(15,0)) ?

    Reply ↓
  19. ildarovich

    (18) Serj1C, в этом случае у меня получалось более громоздкое выражение. Поскольку для выделения одной цифры целое нужно было находить дважды. А по затратам времени, думаю, результаты должны быть примерно одинаковыми. То есть при примерно равных затратах времени выбираем меньшую громоздкость. Такое обоснование.

    Reply ↓
  20. Sgeor

    Пригодился этот метод для таблиц из внешней БД.

    Заметил один момент: в десятках выводились значения на единицу больше (например, вместо значения «10307» выводилось «10317»).

    Проблема решилась после того, как убрал «+1» из «/ 6 + 1» в вычислении десятков. Вот фрагмент:

    ПО (customfieldvalue.STRINGVALUE = «10»
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ВЫРАЗИТЬ(customfieldoption.ID * 0.06 КАК ЧИСЛО(18, 0)))) / 6 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ВЫРАЗИТЬ(customfieldoption.ID * 0.6 КАК ЧИСЛО(18, 0)))) / 6, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, customfieldoption.ID * 6)) / 6 + 1, 1))

    Так что лучше перепроверить перед использованием этого метода.

    Но мне все-равно очень пригодилось, спасибо.

    Reply ↓
  21. ildarovich

    (20) Sgeor, в тексте метода, приведенном в статье, никакого ВЫРАЗИТЬ нет. Этот оператор в этом случае не нужен, он лишний. То, что написано в (20) у меня совсем никак не работает.

    Если же записать в точности так, как написано в статье:

    ВЫБРАТЬ
    10307 КАК Id
    ПОМЕСТИТЬ customfieldoption
    ;
    ВЫБРАТЬ
    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, Id * 0.0006)) / 6 + 1, 1)
    +  ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, Id * 0.006)) / 6 + 1, 1)
    +  ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, Id * 0.06)) / 6 + 1, 1)
    +  ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, Id * 0.6)) / 6 + 1, 1)
    +  ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, Id * 6)) / 6 + 1, 1)
    ИЗ
    customfieldoption КАК customfieldoption

    Показать

    то результат будет совершенно верный: «10307»

    Reply ↓
  22. Sgeor

    (21) не при чем тут вообще «ВЫРАЗИТЬ» — это кусок давнишнего изврата и мракобесия=)

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

    ВЫБРАТЬ
    customfieldoption.ID КАК До,
    «10» + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, customfieldoption.ID * 0.06)) / 6 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, customfieldoption.ID * 0.6 )) / 6 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, customfieldoption.ID * 6)) / 6 + 1, 1) КАК После
    ИЗ
    ВнешнийИсточникДанных.JiraBasina.Таблица.customfieldoption КАК customfieldoption
    

    Результат:

    До—-|—После

    10300 | 10300

    10301 | 10301

    10302 | 10302

    10303 | 10303

    10304 | 10304

    10305 | 10315

    10306 | 10316

    10307 | 10317

    10308 | 10318

    10309 | 10319

    В итоге, если число в предыдущем разряде > 4, то прибавляется ненужная 1. Когда избавился от «+1» в вычислении десятков, все встало на свои места. Когда избавился от «+1» во всех разрядах, снова получил бред. А по твоему коду в (21) все в порядке. Магия.

    Думается, что с ID-шниками в базе что-то странное? Нет — число как число.

    Reply ↓
  23. ildarovich

    (22) Sgeor, я, кажется, понял в чем дело. Есть правило определение точности результатов арифметических операций в запросе в зависимости от точности операндов. Они описаны в статье: Разрядность результатов выражений и агрегатных функций в языке запросов. Видимо, срабатывание этого правила приводит к необходимости привести результат customfieldoption.ID * 0.6 к целому типу! В результате производится не отбрасывание дробной части (как задумано в данном в статье выражении), а округление. Поэтому, видимо, нужно предварительно привести операнд к нужному типу, например, ВЫРАЗИТЬ(Id КАК Число(15, 1)).

    Reply ↓
  24. selenat

    Добрый день. В базах на sql этот запрос нормально отрабатывает, а в базе на постгри — вылетает с ошибкой. Причем даже если делаю ПОДСТРОКА(«»0123456789″», ВЫРАЗИТЬ(СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.06)) / 6 + 0.5 КАК ЧИСЛО(1, 0)), 1) (+0.5 использую, так как ВЫРАЗИТЬ округляет число, а не отбрасывает дробную часть)

    как этому можно помочь?

    Reply ↓
  25. ildarovich

    (24) selenat, а платформа какая? Вообще с Postgre проблемы могут быть, буду разбираться, но быстро не обещаю.

    Reply ↓
  26. selenat

    Платформа 8.3.6.2237

    Reply ↓
  27. olbu

    Не могу сообразить, как имея таблицу дат в запросе и вот этот запрос

    ВЫБРАТЬ
    ПОДСТРОКА(«0123456789», ДЕНЬ(&Дата) / 10 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, 6 * ДЕНЬ(&Дата))) / 6 + 1, 1)
    + «/»
    + ПОДСТРОКА(«0123456789», МЕСЯЦ(&Дата) / 10 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, 6 * МЕСЯЦ(&Дата))) / 6 + 1, 1)
    + «/»
    + ПОДСТРОКА(«0123456789», ГОД(&Дата) / 1000 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 0.06)) / 6 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 0.6)) / 6 + 1, 1)
    + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 6)) / 6 + 1, 1) КАК Строка
    

    Показать

    получить таблицу дат в строковом выражении?

    Reply ↓
  28. ildarovich

    (27) olbu, вам нужно написать запрос примерно такого вида:

    ВЫБРАТЬ <СложноеВыражениеИзСтатьиГДЕПараметр&ДатаЗамененНаНужноеИмяПоляТаблицыДат> КАК ДатаВСтроковомВыражении ИЗ ТаблицаДатВЗапросе

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

    Reply ↓
  29. user633312_i_vi

    ПОДСТРОКА(«01020304050607080910111213141516171819202122232425262728293­031″,ДЕНЬ(&Дата)*2-1,2)+».»

    +ПОДСТРОКА(«010203040506070809101112″,МЕСЯЦ(&Дата)*2-1,2)+».201″

    +ПОДСТРОКА(«0123456789»,ГОД(&Дата)-2010+1,1) КАК СтрДата

    // Тоже не ахти но …

    Reply ↓
  30. ildarovich

    (29) user633312_i_vi, хороший вариант. С месяцами вообще все хорошо, с годом — плохо.Дни — зависит от вкуса. Лично мне нравится. Возможно, стоит комбинировать в одном выражении оба этих подхода.

    Reply ↓
  31. Amur_MVS

    Интересный вариант

    Reply ↓
  32. rpgshnik

    Гениально!

    Reply ↓
  33. nk25

    (3) ну вот увлекается он этим 🙂

    если бы в 1с-ком языке появился pl/sql с хранимыми процедурами то наверно все было по другому

    Reply ↓
  34. kasper076

    При разрядности числа 10 знаков, 3 после запятой

    ПОДСТРОКА(Ц, СЕКУНДА(ДОБАВИТЬКДАТЕ(О, СЕКУНДА, &Число * 6000)) / 6 + 1, 1)

    выдает пустую строку.

    Из-за того, что получается слишком большое число &Число * 6000.

    Этот момент уже разбирался, но я не смог найти где.

    Reply ↓
  35. ildarovich

    (34) Конечно, у «добавить к дате» есть ограничения на величину параметров. И &Число * 6000 не может быть слишком большим. Можно проверить, ограничение порядка 2#k8SjZc9Dxk32, то есть четырехбайтовое целое.

    Это ограничение приведенного приема.

    В этом случае предлагается выделять младшую и старшую часть числа и переводить их по отдельности.

    СтаршаяЧасть = ВЫРАЗИТЬ(&Число / 10000000, КАК Число(15, 0));

    МладшаяЧасть = &Число — СтаршаяЧасть * 10000000.

    Об этом написано в самой статье

    Ограничением рассмотренного подхода является максимальное число секунд при работе с датами. Оно таково, что мы можем выделить не более 10-ти десятичных знаков в числе. Если число значащих знаков больше, исходное число потребуется предварительно разделить на две части «обычным» способом с использованием операции ВЫРАЗИТЬ КАК.
    Reply ↓
  36. kasper076

    (35) В (23) Вы уже объясняли этот момент, но я не понял. В (35) гораздо понятнее. Мож еще кому понятнее будет. Спасибо.

    Reply ↓
  37. trumanl

    Добрый день,

    если не ошибаюсь ЧИСЛО(8, 2) это 123456.78,

    а не 12345678,90

    предложение

    Приведем пример запроса для случая ЧИСЛО(8, 2)

    «» надо исправить на ЧИСЛО(10,2)

    Reply ↓
  38. ildarovich

    (37) Спасибо за уточнение, поправил.

    Reply ↓
  39. =Kollega=

    Расширив вариант (29) можно прийти к следующему:

    ВЫБРАТЬ
    «00010203040506070809» + «10111213141516171819» + «20212223242526272829» + «30313233343536373839» + «40414243444546474849» + «50515253545556575859» + «60616263646566676869» + «70717273747576777879» + «80818283848586878889» + «90919293949596979899» КАК Ц
    ПОМЕСТИТЬ Константа
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    0 КАК Число
    ПОМЕСТИТЬ Числа_0_9
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    1
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    2
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    3
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    4
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    5
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    6
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    7
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    8
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    9
    
    ИНДЕКСИРОВАТЬ ПО
    Число
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    Старший.Число * 10 + Младший.Число КАК Число,
    ПОДСТРОКА(Константа.Ц, (Старший.Число * 10 + Младший.Число) * 2 + 1, 2) КАК Строка
    ПОМЕСТИТЬ Числа_0_99
    ИЗ
    Числа_0_9 КАК Младший,
    Числа_0_9 КАК Старший,
    Константа КАК Константа
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    ВЫБОР
    КОГДА Числа_0_99.Число < 50
    ТОГДА 2000 + Числа_0_99.Число
    ИНАЧЕ 1900 + Числа_0_99.Число
    КОНЕЦ КАК Год,
    ВЫБОР
    КОГДА Числа_0_99.Число < 50
    ТОГДА «20» + ПОДСТРОКА(Константа.Ц, Числа_0_99.Число * 2 + 1, 2)
    ИНАЧЕ «19» + ПОДСТРОКА(Константа.Ц, Числа_0_99.Число * 2 + 1, 2)
    КОНЕЦ КАК ГодСтрокой
    ПОМЕСТИТЬ Годы
    ИЗ
    Числа_0_99 КАК Числа_0_99,
    Константа КАК Константа
    ;
    
    ////////////////////////////////////////////////////////////­////////////////////
    ВЫБРАТЬ
    Числа_0_99.Число КАК Число,
    Числа_0_99.Строка КАК Строка
    ИЗ
    Числа_0_99 КАК Числа_0_99
    
    ОБЪЕДИНИТЬ ВСЕ
    
    ВЫБРАТЬ
    Годы.Год,
    Годы.ГодСтрокой
    ИЗ
    Годы КАК Годы
    
    УПОРЯДОЧИТЬ ПО
    Число
    

    Показать

    Используя одну констатнту можно переводить годы в интервале 100 лет (в примере с 1950 по 2049), месяцы, дни, часы, минуты и секунды.

    Reply ↓
  40. puzakov

    Идея интересная, но… Не дай бог встретить подобное в промышленной БД *представил, перекрестился и плюнул три раза через плечо*

    Reply ↓
  41. sanek050388

    (3) Согласен.

    Reply ↓
  42. ildarovich

    (41)

    Сказали мне, что эта дорога меня приведёт к океану смерти,

    И я с полпути повернула вспять.

    С тех пор все тянутся предо мною кривые, глухие окольные тропы…
    Reply ↓
  43. AlexanderKai

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

    Reply ↓
  44. IVANTHESPACEBIKER

    (5)

    ВЫБРАТЬ
    ВЫБОР
    КОГДА &Число / 10000000 > 1
    ТОГДА ПОДСТРОКА(«0123456789», &Число / 10000000 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 1000000 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.000006)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 100000 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.00006)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 10000 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.0006)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 1000 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.006)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 100 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.06)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 10 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 0.6)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + ВЫБОР
    КОГДА &Число / 1 > 1
    ТОГДА ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 6)) / 6 + 1, 1)
    ИНАЧЕ «»
    КОНЕЦ + «.» + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 60)) / 6 + 1, 1) + ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, &Число * 600)) / 6 + 1, 1) КАК Строка
    

    Показать

    Reply ↓
  45. redfox64

    Интересно что в Postgre получаю неверный год. Вместо 2018 — 2028.

    Reply ↓
  46. ildarovich

    (45) А что получается, если просто

    ВЫБРАТЬ Год(&Дата)
    Reply ↓
  47. redfox64

    (46)

    ВЫБРАТЬ Год(&Дата)

    2018

    Reply ↓
  48. RotaninV

    (43) что самое интересное, на 8.0, до 2-3 релиза он был и вполне себе работал.

    Reply ↓
  49. IvanVL

    Ага, дошло, долго понять не мог «что функция СЕКУНДА фактически является функцией остатка от деления на 60 числа секунд»,

    как понял, все стало понятно.

    Reply ↓
  50. bajiepka

    Попробовал последний запрос на PostgreSql (linux). Как и писалось выше работает некорректно, видимо из-за округления или характерного для этой субд механизма получения дат. Это ни в коем случае не попытка «обхаить». Будьте бдительны с PostgreSQL.

    Reply ↓
  51. ser6702

    (4) плюсую… как гимнастике ума не более. Инога этим сам страдаю. Но на самом деле вредная статья. Поясню:

    Приведен перечень ссылок на вопросы, но вопросы эти ползут от … непонимания — не так ли?

    Сам на первых этапах при переходе от скуля и ора (с,паскаль) задавал сначала такие. На самом деле есть два мощных серврера СУБД и 1С, которые надо полномасштабно использовать. Не передавая на СУБД те задачи, которые ей не предназначены.

    Пример:

    В одной из конфигураций ( разработка внутренняя ) для ведения административно хозяйственной деятельности банка весь расчет амортизации ОС перенесли на запрос. А зачем спрашиваю? СУБД для 1С в основном служит для быстрого поиска… хранения данных и т.д. Все расширения типа pl/sql по сути реализованы в языке … сервера приложений 1С. Кластер СУБД , им рулят его админы, и кластер 1С — оба мощные вычислительные комплексы. Сервер приложений 1С это тоже мощная машина с огромными ресурсами, которые надо использовать. Оптимизация состоит в том, чтобы с клиента один раз обратиться к серверу приложений 1С, с него за раз получить данные из субд и вернуть обратно через сервер приложений 1С на клиента. Опустил пока вопрос записи — объектная модель конечно по сравнению с табличной проигрывает, но зато взаимное поведение объектов относительно друг друга всегда предсказуемо.

    Не надо кластер СУБД нагружать ему не предназначенными задачами — надо их верно перераспределять между кластерами СУБД и 1С.

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

    Reply ↓
  52. taasha25

    Спасибо! Мне пригодилось.

    Reply ↓
  53. FilatovRA

    (6) Практический пример: Есть данные о неких внутренних идентификаторах номенклатуры, приведенных в справочнике с реквизитами «Номенклатура»(Справочник-номенклатура) и «Идентификатор»(Число).

    Пример записи:

    Маршрутизатор 12345678

    Есть запись справочника «Номенклатура» введенная вручную, вида:

    «Маршрутизатор 12345678 ПонятияНеИмеюЗачемЭтиЦифры».

    Задача: заполнить некий регистр, хранящий записи о соответствиях этих 2х записей.

    Reply ↓
  54. starik-2005

    А вот возник вопрос: а как теперь из получившейся строки убрать лидирующие нули? Мне, например, нужен диапазон какой-то, который я вычислил. В итоге он может быть от какого-нить нуля до какого-нить миллиона, но выводить «00000001-1000000» — как-то некошерно, однако. Есть мысли на эту тему? Первое, что приходит в голову — это поиск минимального «ненуля» и подстрока от позиции ненуля до конца строки. Остается придумать, как оптимально найти первый ненуль.

    Reply ↓
  55. golod

    Спасибо автору поста, очень помогли

    Reply ↓
  56. falexru

    ВЫБРАТЬ

    ВЫБОР

    КОГДА Не ПОДСТРОКА(&Номер, 1, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 1, 10)

    КОГДА Не ПОДСТРОКА(&Номер, 2, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 2, 9)

    КОГДА Не ПОДСТРОКА(&Номер, 3, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 3, 8)

    КОГДА Не ПОДСТРОКА(&Номер, 4, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 4, 7)

    КОГДА Не ПОДСТРОКА(&Номер, 5, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 5, 6)

    КОГДА Не ПОДСТРОКА(&Номер, 6, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 6, 5)

    КОГДА Не ПОДСТРОКА(&Номер, 7, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 7, 4)

    КОГДА Не ПОДСТРОКА(&Номер, 8, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 8, 3)

    КОГДА Не ПОДСТРОКА(&Номер, 9, 1) = «0» ТОГДА ПОДСТРОКА(&Номер, 9, 2)

    Иначе ПОДСТРОКА(&Номер, 10, 1)

    КОНЕЦ КАК СтрокаБезЛидирующихНулей

    Reply ↓
  57. antonkms88

    Запрос 1С округляет по математическим правилам. Поэтому, представленный перевод из даты в строку не всегда отрабатывает корректно. Пример: 29.08.1995

    Добавил немного, чтобы округления возвращали необходимые значения.

    ПОДСТРОКА(«0123456789», ДЕНЬ(&Дата) / 10 + 0.5, 1),

    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, 6 * ДЕНЬ(&Дата))) / 6 + 0.5, 1),

    «/»,

    ПОДСТРОКА(«0123456789», МЕСЯЦ(&Дата) / 10 + 0.5, 1),

    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, 6 * МЕСЯЦ(&Дата))) / 6 + 0.5, 1),

    «/»,

    ПОДСТРОКА(«0123456789», ГОД(&Дата) / 1000 + 0.5, 1),

    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 0.06 — 0.5)) / 6 + 0.5, 1),

    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 0.6 — 0.5)) / 6 + 0.5, 1),

    ПОДСТРОКА(«0123456789», СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, ГОД(&Дата) * 6 — 0.5)) / 6 + 0.5, 1)

    Reply ↓
  58. OksDallas

    Внесу свои пять копеек по преобразованию даты в строку

    Запрос = Новый Запрос;
    
    Запрос.Текст =
    «ВЫБРАТЬ
    | ОтзывыИзОтпуска.Сотрудник КАК Сотрудник,
    | ОтзывыИзОтпуска.ПриказОбОтзыве,
    | ДЕНЬ(ОтзывыИзОтпуска.Период) КАК День,
    | МЕСЯЦ(ОтзывыИзОтпуска.Период) КАК Месяц,
    | ГОД(ОтзывыИзОтпуска.Период) — 2000 КАК Год
    |ПОМЕСТИТЬ ВТ_ОтпускСОтзывами
    |ИЗ
    | РегистрСведений.ОтзывыИзОтпуска КАК ОтзывыИзОтпуска
    |ГДЕ
    | ОтзывыИзОтпуска.Сотрудник В(&Сотрудник)
    |
    |ИНДЕКСИРОВАТЬ ПО
    | Сотрудник
    |;
    |
    |////////////////////////////////////////////////////////////­////////////////////
    |ВЫБРАТЬ
    | ВТ_ОтпускСОтзывами.Сотрудник,
    | «»Пр.№ «» + ВТ_ОтпускСОтзывами.ПриказОбОтзыве + «» от «» + ВЫБОР
    |  КОГДА ВТ_ОтпускСОтзывами.День < 10
    |   ТОГДА «»0″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.День + 1, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.День < 20
    |   ТОГДА «»1″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.День — 9, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.День < 30
    |   ТОГДА «»2″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.День — 19, 1)
    |  ИНАЧЕ «»3″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.День — 29, 1)
    | КОНЕЦ + «».»» + ВЫБОР
    |  КОГДА ВТ_ОтпускСОтзывами.Месяц < 10
    |   ТОГДА «»0″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Месяц + 1, 1)
    |  ИНАЧЕ «»1″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Месяц — 9, 1)
    | КОНЕЦ + «».20″» + ВЫБОР
    |  КОГДА ВТ_ОтпускСОтзывами.Год < 10
    |   ТОГДА «»0″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Год + 1, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.Год < 20
    |   ТОГДА «»1″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Год — 9, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.Год < 30
    |   ТОГДА «»2″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Год — 19, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.Год < 40
    |   ТОГДА «»3″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Год — 29, 1)
    |  КОГДА ВТ_ОтпускСОтзывами.Год < 50
    |   ТОГДА «»4″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.Год — 39, 1)
    |  ИНАЧЕ «»5″» + ПОДСТРОКА(&Циферки, ВТ_ОтпускСОтзывами.День — 49, 1)
    | КОНЕЦ + «» г.»» КАК Приказ
    |ИЗ
    | ВТ_ОтпускСОтзывами КАК ВТ_ОтпускСОтзывами»;
    
    Запрос.УстановитьПараметр(«Циферки», «0123456789»);
    

    Показать

    Reply ↓
  59. YalanchidiO
    Reply ↓
  60. ildarovich

    (57) Не могу подтвердить.

    У меня, наоборот, мой код из статьи дает на примере 29.08.1995 совершенно верный результат, а ваш код дает 28/07/1984 на этих данных.

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

    Reply ↓
  61. ildarovich

    (59) Хочу разобраться: чем не устроил запрос из статьи? Способ округления я учитывал, когда составлял запрос и тестировал подход, но все может быть…

    Какая у вас СУБД? Давайте я протестирую свой подход на ваших данных (нужно немного времени). Вообще я против такой громоздкости, даже если она работает.

    Reply ↓
  62. ildarovich
    Reply ↓
  63. antonkms88

    (60)

    Да, от СУБД, судя по всему, зависит.

    В приложении 2 картинки. Одна картинка — серверная база с СУБД Postg, другая картинка — файловая база.

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

    Reply ↓
  64. Aleks9111

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

    Reply ↓
  65. _Sedoy

    Может я что-то не понимаю, но…

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

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

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

    Возвращаемое значение – представление значения, тип СТРОКА.

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

    Пример:

    ВЫБРАТЬ
    ПРЕДСТАВЛЕНИЕ(РасхНакл.Получатель) КАК ПолучательСтрокой,
    ПРЕДСТАВЛЕНИЕ(РасхНакл.Дата) КАК ДатаСтрокой
    ИЗ
    Документ.РасхНакл КАК РасхНакл
    Reply ↓

Leave a Comment

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