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




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

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

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

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

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 не будет опубликован. Обязательные поля помечены *