Здравствуйте! Сталкивался кто-нибудь с оптимизацией циклов. Нужно сократить время выполнения данного цикла до минут (сейчас на нескольких тысяч строк таблицы работает несколько часов):
for i = 1 to Таблица.Количество() - 1 do
for j = 1 to Таблица.Количество() - i do
if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора
and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета
and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
ВидОперацииТекущий = Строка(Таблица[j].ВидОперации.ПриходРасход);
ВидОперацииПредыдущий = Строка(Таблица[j - 1].ВидОперации.ПриходРасход);
if ВидОперацииТекущий = "Приход" and ВидОперацииПредыдущий = "Расход" then
Таблица.Сдвинуть(j, -1);
endif;
endif;
enddo;
enddo;
(1) изменить логику - понять смысл сдвигания строк и сделать по-другому , например как вариант нужно поле сортировки но его нет - добавить к ТЗ колонку - пройтись один раз нужным образом заполнить - отсортировать по колонке
(1)
У меня такое чувство, что здесь вся сортировка для того чтобы приходы были раньше расходов в рамках одной аналитики.
А если отсортировать по аналитике сравнения (валюта, договор, место, дата) по возрастанию, и потом по виду операции - это не тоже самое будет?
Или если изначально строки не подряд в рамках аналитики их не нужно сортировать?
if ВидОперацииТекущий = "Приход" and ВидОперацииПредыдущий = "Расход" then
Таблица.Сдвинуть(j, -1);
endif;
Если условие отработало, то произвели смещение, тогда на следующей итерации всегда будет ВидОперацииПредыдущий = "Приход" и хоть запроверяся всеми условиями. Как по мне внутрь этого условия надо положить наращивание j-того: j = j + 1;
Больше оптимизировать данную логику, мне кажется, не получится. После этих правок узким горлышком будет операция смещения.
Я бы похоронил бы этот алгоритм и создал бы один цикл с перебором с конца, так как суть этого двойного цикла именно в этом. Этим перебором заполнял новую таблицу с теми же колонками, но добавив ещё одну со своим индексом, так как перебор с конца вывернет новую таблицу с зада на перед, а по этому индексу в конце перебора просто бы наложил сортировку.
(27)А зачем мне у автора спрашивать где находится таблица? Тут явно видно обращения через точку: Таблица[j - 1].ВидОперации.ПриходРасход, где ВидОперации - это реквизит таблицы.
Далее - это преобразование этого всего в тип строка, что тоже вызывает СУБД и нет разницы где расположена таблица.
(30) ВидОперации - это справочник? документ? может быть, структура? всегда ли там будет обращение к субд?
Но вообще да, скорее всего, там обращение через точку в цикле к объекту ссылочного типа - а это ай-яй-яй
(21)В объектной модели при получении реквизитов через точку объект кешируется.
Поэтому если там пара видов операций, то как бы именно в этом особой проблемы тут нет.
(33)Объект, от которого берется реквизит.
ВидОперации.ПриходРасход
очевидно, что ВидОперации, это ссылка, вероятно, на справочник.
Поэтому если в коде от одной ссылки взять 2 реквизита:
МояСсылка.Реквизит1
МояСсылка.Реквизит2
То при первом обращении через точку - для Реквизит1 весь объект прочтется в кэш. И эта операция будет относительно долгой.
И на строке Реквизит2 и другим обращениям к реквизитам будет уже данные из кэша. И эта операция будет уже быстрой.
Поэтому, если нужно получить единоразово 1-2 реквизита у объекта, а весь объект не нужен, то обычно используют функции БСП, которые получают только нужные реквизиты через запросы.
&НаСервереБезКонтекста
Процедура Команда1НаСервере()
Для а = 1 по 200 Цикл
Б = Строка(Справочники.ВидыВычетовНДФЛ.Код103);
Сообщить(Б);
КонецЦикла;
КонецПроцедуры
&НаКлиенте
Процедура Команда1(Команда)
Команда1НаСервере();
КонецПроцедуры
Показать
И посмотрел трассу - 1 запрос к субд
Соответственно, реквизит он посчитал 1 раз. Ну т.е. некоторые вещи сервер 1С умеет кэшировать, когда ему это надо.
и даже потом заменил
Б = Строка(Справочники.ВидыВычетовНДФЛ.Код103.ГруппаВычета);
все равно - 1 запрос.
Тоже самое тут у автора - у него всего 2 варианта - приход и расход, они, с высокой степенью вероятности, также закэшируются 1 раз и до конца обработки живут.
Хотя полностью осуждаю тех, кто обращается через точку. Это ай-яй-яй, и полагаться на сервер 1С в данном случае не хорошо.
(35)Допустим это справочник, то тогда можно предположить, что значение ВидОперации в первой строке может быть не равно значению во второй, и тогда кэширование платформы не даст максимального результата.
Так же, насколько я вас понял, то данная неоднозначность вполне допустима. Как предположил user1274438, что это может быть просто структура, тогда тут вообще может и не быть серверного вызова.
Моё мнение, неоднозначности быть не должно. Ситуации, когда ты не можешь предсказать поведение кода без его отладки меня настораживают.
По логике, тут двойной вызов сервера, для большого количества строк может быть критичным.
Избавился от этого. На этапе создания Таблицы (= таблица значений) добавил новый столбец ПриходРасход. В цикле обращаюсь к столбцу непосредственно.
То есть код стал такой:
for i = 1 to Таблица.Количество() - 1 do
for j = 1 to Таблица.Количество() - i do
if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора
and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета
and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
if Таблица[j].ПриходРасход = "Приход" and Таблица[j - 1].ПриходРасход = "Расход" then
Таблица.Сдвинуть(j, -1);
endif;
endif;
enddo;
enddo;
Показать
В итоге, время формирования отчета уменьшилось до 2 час 18 минут (против более 4 часов).
Сохраните таблицу после сортировки вашей процедурой в табличный документ.
Выполните сортировку таблицы стандартным методом таблицы значений, как предложено выше и сохраните во второй табличный документ.
Далее можно сравнить табличные документы в сравнением файлов.
Отличаются ли результаты?
Если отличаются, то это отличие влияет на что-нибудь?
(46) Ваш цикл меняет строки местами, то есть сортирует.
Нужно сравнить 2 варианта реализации.
1 - ваш.
2 - вариант из (32) только в полях сортировки указать все поля, по которым сравниваются в вашем цикле.
Сравнить можно, например, сохранив таблицы в табличных документах в режиме Отладки, из Табло.
(44) Смотри. Очевидно, что исходная таблица уже отсортирована по Валюта/Место/Номер/Дата. Иначе бы не получалось сравнивать по имеющемуся условию соседние строки. Что выполняет этот код? Он сортирует по Приход/Расход в рамках комбинации группировок Валюта/Место/Номер/Дата, оставляя остальной порядок строк нетронутым (вероятно, есть дополнительные сортировки по каким-то полям. Может, по времени операции и еще чему-то). По-сути, строки с "приходом" просто "всплывают" наверх в рамках комбинаций группировок Валюта/Место/Номер/Дата.
Самый эффективный способ оптимизировать - это использовать стандартное Сортировать(). Но для этого нужно понять, какие еще поля кроме Валюта/Место/Номер/Дата/ВидОперации нужно включить в выражение сортировки. Возможно, нужно добавить какие-то доп-поля, если их сейчас нет.
Скорее всего, необходима сортировка по Валюта/Место/Номер/Дата/ВидОперации/ВремяОперации или типа того.
Это будет самый эффективный по производительности вариант (эффективнее только сортировать еще в СУБД)
(44) Хороший результат.
Давайте ещё попробуем избавиться от двойного цикла и просто перебрать с конца:
j = Таблица.Количество() - 1;
While j <> 0 do
if Таблица[j].ВалютаРасчетов = Таблица[j - 1].ВалютаРасчетов
and Таблица[j].НомерДоговора = Таблица[j - 1].НомерДоговора
and Таблица[j].МестоУчета = Таблица[j - 1].МестоУчета
and Таблица[j].ДатаОперации = Таблица[j - 1].ДатаОперации then
if Таблица[j].ПриходРасход = "Приход" and Таблица[j - 1].ПриходРасход = "Расход" then
Таблица.Сдвинуть(j, -1);
endif;
endif;
j = j - 1;
enddo;
Показать
По формулам арифметической прогрессии в вашем алгоритме на 1000 строк получится почти 500 тысяч вызовов сравнения ваших 4-х реквизитов в верхнем условии, а операция сравнения тоже может отжимать хорошее время. Если перебирать таблицу с конца, то двойного цикла не нужно, и на 1000 строк у вас будет 1000 вызовов. На теории должно дать значительный прирост, но с практикой может разойтись. Если результат будет слабый, то тогда сортировка или пересоздание таблицы, так как будет ясно, что единственный затык в сдвиге.
По коду, это изуверство, мне тоже в своё время в наследство досталось такое чудо, половина на русском, половина на латинице с использованием переменных с именами как у вас. Рефакторить это всё было тихим ужасом, приходилось выписывать имена переменных и составлять из них словарь. Например, tbTvr (таблица товаров в документе), tbTost (таблица остатков товаров на складе) и так далее, кайф.
(54) Просто перебор с конца не даст правильный результат, я тоже начал думать в эту сторону, но плюнул т.к. чтобы получить правильный результат придется еще костылей натыкать.
Смотри, если есть такая последовательность:
Приход
Расход
Приход
Приход
то последний приход "всплывать" не будет. А должен.
(55)Согласен, если таблица именно такая, то это печально и верно работать от обратного не будет. Так же простая сортировка тоже, увы, не решение. Пересоздание таблицы превращается тоже в костылестроение, красивое решение не приходит на ум. Интересная задачка.
(63)ТС боится менять алгоритм, так понимаю, чтоб не сломать, т.к. не понимает что он делает и зачем. Поэтому из всех советов воспринимает только те, что не затрагивают сам алгоритм.
(64) Это понятно. И тут ему тоже сложно помочь, так как ТС до сих пор не удосужился сделать замер производительности, чтобы определиться с направлением оптимизации.
Возможно, достаточно будет оптимизировать кэширование "черезточечных" значений. Подозреваю, что сейчас это сделано "в лоб".
Возможно, узким местом является операция сдвига строки в ТЗ. Тут тоже есть идеи.
Возможно, явных узких мест нет и дело в количестве итераций и перестановок - тут тоже есть простор для оптимизации.
В чём смысл был в изобретении этого чуда не известно, но он явно должен быть. Таблица имеет некий порядок и раз сравнение только по этим колонкам, а сдвиг только по одной, то порядок, который есть до начала циклов в таблице важен для конечного результата.
К тому же:
(58)
Вполне может оказаться, что достаточную оптимизацию можно получить и не изобретая очередную вариацию алгоритмов сортировки.
порядок, который есть до начала циклов в таблице важен для конечного результата.
Так я и предлагаю осознать смысл этого доп-порядка и сохранить это доп-упорядочивание введением дополнительных ключей сортировки (за один проход) если сейчас их нет. Могу предположить, что для получения этих доп-ключей необходимо обращение к БД и автору показалось проще просто попытаться сохранить оригинальное упорядочивание.
(65)Даже не знаю какой тут пример сообразить. Вот приезжают туристы в Москву, шарются по метро и глазеют на потолки, трут бронзовые постаменты, а ты об них спотыкаешься со словами: что тут интересного, это же просто метро, общественный транспорт. Глубинный смысл моего интереса объяснять не имею желания.
(70) если вы хотите искать глубинный смысл там, где его нет, то вам сюда https://www.govnokod.ru/1c , многие философы сошли с ума в понимании замыслов творений этих авторов. В принципе решение из (32) верное, однако я бы поменял на Таблица.Сортировать("ВалютаРасчетов, НомерДоговора, МестоУчета, ДатаОперации, Приоритет");
где Приоритет определяется по виду операции.
либо тоже самое предложено в (53).
Тип: Строка.
Список имен колонок, разделенных запятыми, по которым производится сортировка таблицы. После каждого имени колонки через пробел может быть указано направление сортировки. Направление определяется: "Убыв" ("Desc") - упорядочивать по убыванию; "Возр" ("Asc") - упорядочивать по возрастанию. По умолчанию сортировка производится по возрастанию. Порядок указания имен колонок таблицы определяет порядок сортировки. Это означает, что сначала таблица сортируется по колонке, указанной первой. Затем группы строк с одинаковым значением в этой колонке сортируются по колонке, которая указана второй, и так далее.
Получается, что сортировкой по первой колонке мы сразу же ломаем ту сортировку, что первоначально была заложена при построении таблицы. Может получиться ситуация, когда строка, которая не должна была по первоначальному алгоритму сместиться, поменяет свою дислокацию. Нет, можно надеется на то, что здесь нет глубинного смысла, то тогда всё будет работать верно, но настораживают слова ТС, что алгоритм работает правильно, хотя и долго. А раз так, то есть вероятность, что смысл в этом алгоритме есть.
Не знаю, я видимо оптимист, так как считаю, что человек, который писал код, всё же таки думал, а не бил головой об клавиатуру.
Если порядок в результате не важен, то применяем сортировку и дело с концом. ТС же пришёл с просьбой оптимизировать что есть. Мы же вступили в полемику на гране срача и в конечном итоге только и делаем что гадаем на кофейной гуще.
Смысла дальше продолжать я теперь не вижу для себя, так как последнее что я слышу: "тебе больше всех надо? Тут нужна только стандартная сортировка". Я про неё ещё в своём первом комментарии сказал. Приходят, вырывают из контекста, перефразируют. Надоело.
Получается, что сортировкой по первой колонке мы сразу же ломаем ту сортировку, что первоначально была заложена при построении таблицы
, а зачем тогда нужен весь алгоритм, если сортировка не такая как в решении? в примере ясно показано, что строка сдвигается вверх, если предыдущая имеет одинаковые поля. Какой смысл вообще сортировать данную выборку, если она имеет хаотический порядок. Вы хватаетесь только за часть, но не видите всей картины.
Не знаю, я видимо оптимист, так как считаю, что человек, который писал код, всё же таки думал, а не бил головой об клавиатуру.
Так смотрите, уже привели пример кода, когда человек не думает о решении.
Смысла дальше продолжать я теперь не вижу для себя, так как последнее что я слышу: "тебе больше всех надо? Тут нужна только стандартная сортировка". Я про неё ещё в своём первом комментарии сказал. Приходят, вырывают из контекста, перефразируют. Надоело.
Не знал, что своими комментариями, я задел ваши чувства, не расстраивайтесь - все будет хорошо. Желаю вам прекрасного не тормозящего кода;)
ефакторить это всё было тихим ужасом, приходилось выписывать имена переменных и составлять из них словарь. Например, tbTvr (таблица товаров в документе), tbTost (таблица остатков товаров на складе) и так далее, кайф.
Нафига выписывать? Я когда такое рефакторю, то как только понимаю смысл переменной сразу ее везде меняю через "найти и заменить".
Я просто боялся это делать в базе, в которой любое движение вызывало лавину из ошибок. Да и этот код лежал на веб-сервисе для мобильного приложения, написанного на JS, логика была в том, что наименования переменных в этом приложении было равно наименованиям в 1С, поэтому понять что это за переменная было проще, но всё же вызывало боль.
(54) Другими словами, в общем случае за "один проход" это не решить. Необходимо тем большее количество итераций, чем "хуже" изначальная сортировка. В каких-то случаях придется "возвращаться" и не один раз.
Но значительно оптимизировать количество итераций и перестановок безусловно можно. Вопрос только, стоит ли? Вполне может оказаться, что достаточную оптимизацию можно получить и не изобретая очередную вариацию алгоритмов сортировки.
таб = таблица.скопировать(); //или выгрузить Перемещаем талицузначений (в оперативную память)
ОписаниеТипа = Новый ОписаниеТипов("Число",
Новый КвалификаторыЧисла(1, 0));
таб.колонки.добавить("Приход", ОписаниеТипа);
для каждого ном из рез Цикл
ВидОперацииТекущий = Строка(ном.ВидОперации.ПриходРасход);
Если ВидОперацииТекущий = "Приход" тогда
ном.Приход = 1;
иначе
ном.Приход = 2;
КонецЕсли;
КонецЦикла;
таб.сортировать("ДатаОперации,ВалютаРасчетов,МестоУчета,НомерДоговора,Приход");
таблица.загрузить(таб);
Показать
Если сортировка не подходит то
1. необходимо поделить таблицу пополам, а вторую фильтровать
2. если работать с 2-умя идентичными талицами будет быстрее так как не будет задержек сдвига в первой таблице.
(4) а Таблица куда потом передается или что с ней дальше делается?
не рассматривали вариант просто перезаполнить новую таблицу уже отсортированными данными?
поучится быстрее, чем двигать строки
)) Код работающий, то есть дает правильный результат. Когда делал, тестировал на нескольких днях максимум и было не так ощутимо. Но столкнулись с месячным отчетом и оказалось слишком медленно формирует результат.
Есть конкретная строка таблицы. Нужно взять эту строку и сравнить по условию со всеми строками таблицы. Если условие выполняется, то нужно поменять местами текущую строку и соседнюю. И так сделать для каждой строки таблицы. В итоге строки перемешаются и встанут как нужно.
В конфигураторе есть средства отладки позволяющие сделать замер времени какие строки сколько процессорного времени расходуют, уверен что самая тормознутая операция это перемещение строки.
Вы сдвигаете строчки по одной позиции.
Необходимо сделать таблицу соответствия строк реальной таблицы с тем какие номера строк вы в итоге хотели бы получить. Не сдвигать строки а менять их номер в таблице индексов.
После формирования таблицы индексов каждую строку в таблице сдвинуть ровно один раз не по одной строке а сразу туда куда нужно типа
Таблица.Сдвинуть(j, -17);
Но мне больше нравится вариант не с перемещением строк а с заполнением другой ТЗ исходя из имеющейся и с обратным копированием уже готовой ТЗ.
По коду кажется что для удобства пользователя строки с одинаковыми реквизитами, но с разными ВидамиОпераций идут друг за другом (?)
Если я правильно понял, тогда так можно сделать
(17)
1 шаг - через отбор разделить ТЗ на 2: с Приходом и Расходом, (2-3 сек)
2 шаг - добавить в каждую таблицу по столбцу (пусть "Номер", Число), 1 таблицу "ТЗ_Приход" заполнить "Номер" нечетными числами , 2 таблицу "ТЗ_Расход" заполнить четными числами, (10 сек)
3 шаг - объединить обе таблицы и сортировать по реквизитам по которым сравнение в цикле + по новому "Номер" - тогда все по порядку будет, а Приход/Расход друг за другом.
*это сработает если условно одинаково приходов/расходов, если есть непарные строки, то другой алгоритм, но с 1 циклом.
Надо с алгоритмом подумать.
Я так понял, тут идея в том, чтобы в одинаковых строках сначала шли приходы, а потом расходы.
Я бы, наверное, добавил пару колонок: 1) сделал бы в каждой строке ключ вида "" + Валюта + Место + ... что там входит в ключ и 2) порядок: приход = 1, расход - 2
потом простой сортировкой задача решается без многоразового прохода таблицы (кмк тут даже оценить количество проходов не так-то просто).
ЗЫ ключи, если есть возможность, заполнить на стадии заполнения таблицы, будет еще быстрее.
(19) Да можно просто отсортировать по нужным полям, включая приход/расход.
Но автор же сказал, что не знает однозначного способа сортировки. Ну и пусть дальше не знает.
(22) нет, просто сортировать не получится, т.к. нам нужна сортировка по виду операции только в пределах ключа из четырех (или сколько их там) колонок.
Поэтому и не знает, что тут для сортировки нужна еще одна колонка.
Задача вообще не сложная, но способ ее решения внушает. Таланты среди нас )
Можно еще добавить вспомогательную колонку в ТЗ в ней заполнить номера позиций в которых в итоге должна оказаться строка, потом применить команду Сортировать и удалить эту вспомогательную колонку
(32)Поддержу.
Сортировать по всем колонкам, по которым сравнение в текущей процедуре.
И только если этот вариант не подходит, имеет смысл заморачиваться.
size_Таблица = Таблица.Количество();
for i = 1 to size_Таблица - 1 do
for j = 1 to size_Таблица - i do
if Таблица[j].Ключ_ВалютаДоговорМестоУчетаДатаОперации = Таблица[j - 1].Ключ_ВалютаДоговорМестоУчетаДатаОперации then
if Таблица[j].ПриходРасходБулево and NOT Таблица[j - 1].ПриходРасходБулево then
Таблица.Сдвинуть(j, -1);
endif;
endif;
enddo;
enddo;
Показать
Время выполнения сократилось до 1 часа 05 минут (против 2 час. 18 мин и более 4 часов в начале).
Существенный прирост дала замена блока нескольких условий на одно сравнение!
Пока так и не придумал, как здесь правильно избавиться от вложенного цикла так, чтобы результаты не поломались. Сортировка таблицы уже была. Перед этим блоком у меня как раз и написано:
Рассматриваемый код выполняет дополнительное упорядочивание ранее отсортированной таблицы, так как сортировка не дает нужного результата (правильного расположения строк таблицы).
В принципе пока что меня результат устраивает. Спасибо!
ВЫБРАТЬ
АВТОНОМЕРЗАПИСИ() КАК НомерСтроки,
ВЫРАЗИТЬ(МояТаблица.ВалютаРасчетов КАК Справочник.Валюты) КАК Валюта,
ВЫРАЗИТЬ(МояТаблица.ДатаОперации КАК ДАТА) КАК ДатаОперации,
ВЫРАЗИТЬ(МояТаблица.МестоУчета КАК Справочник.Склады) КАК МестоУчета,
ВЫРАЗИТЬ(МояТаблица.Договор КАК Справочник.СоглашенияСПоставщиками) КАК Договор,
ВЫРАЗИТЬ(МояТаблица.ВидДвижения КАК БУЛЕВО) КАК ВидДвижения
ПОМЕСТИТЬ МояТаблица
ИЗ
&МояТаблица КАК МояТаблица
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МояТаблица.НомерСтроки КАК НомерСтроки,
"000000000" + МояТаблица.Валюта.Код КАК Аргумент
ПОМЕСТИТЬ ВТ_Транспонированная
ИЗ
МояТаблица КАК МояТаблица
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
МояТаблица.НомерСтроки,
"1000" + ПОДСТРОКА("01020304050607080910111213141516171819202122232425262728293031", ДЕНЬ(МояТаблица.ДатаОперации) * 2 - 1, 2) + ПОДСТРОКА("010203040506070809101112", МЕСЯЦ(МояТаблица.ДатаОперации) * 2 - 1, 2) + ПОДСТРОКА("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)
ИЗ
МояТаблица КАК МояТаблица
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
МояТаблица.НомерСтроки,
"2" + МояТаблица.МестоУчета.Код
ИЗ
МояТаблица КАК МояТаблица
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
МояТаблица.НомерСтроки,
"3" + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.000000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.0000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.000006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.00006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.0006)) / 6 + 1, 1) + ПОДСТРОКА("0123456789", СЕКУНДА(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), СЕКУНДА, МояТаблица.Договор.Код * 0.006)) / 6 + 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)
ИЗ
МояТаблица КАК МояТаблица
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
1 КАК Позиция,
1 КАК ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд
ОБЪЕДИНИТЬ
ВЫБРАТЬ
2,
31
ОБЪЕДИНИТЬ
ВЫБРАТЬ
3,
961
ОБЪЕДИНИТЬ
ВЫБРАТЬ
4,
29791
ОБЪЕДИНИТЬ
ВЫБРАТЬ
5,
923521
ОБЪЕДИНИТЬ
ВЫБРАТЬ
6,
28629151
ОБЪЕДИНИТЬ
ВЫБРАТЬ
7,
887503681
ОБЪЕДИНИТЬ
ВЫБРАТЬ
8,
1742810335
ОБЪЕДИНИТЬ
ВЫБРАТЬ
9,
2487512833
ОБЪЕДИНИТЬ
ВЫБРАТЬ
10,
4098453791
ОБЪЕДИНИТЬ
ВЫБРАТЬ
11,
2498015937
ОБЪЕДИНИТЬ
ВЫБРАТЬ
12,
129082719
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ПОДСТРОКА("0123456789", СтепеннойРяд.Позиция, 1) КАК Символ,
СтепеннойРяд.Позиция КАК Код
ПОМЕСТИТЬ КодоваяТаблица
ИЗ
СтепеннойРяд КАК СтепеннойРяд
ИНДЕКСИРОВАТЬ ПО
Символ
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИсходныеДанные.НомерСтроки КАК НомерСтроки,
ПОДСТРОКА(ИсходныеДанные.Аргумент, СтепеннойРяд.Позиция, 1) КАК СимволКода,
СтепеннойРяд.ЧленРяда КАК ЧленРяда
ПОМЕСТИТЬ ОтдельныеСимволы
ИЗ
ВТ_Транспонированная КАК ИсходныеДанные,
СтепеннойРяд КАК СтепеннойРяд
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ОтдельныеСимволы.НомерСтроки КАК НомерСтроки,
СУММА(ОтдельныеСимволы.ЧленРяда * КодоваяТаблица.Код) КАК Хэш
ПОМЕСТИТЬ ВыходныеДанные
ИЗ
ОтдельныеСимволы КАК ОтдельныеСимволы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ КодоваяТаблица КАК КодоваяТаблица
ПО ОтдельныеСимволы.СимволКода = КодоваяТаблица.Символ
СГРУППИРОВАТЬ ПО
ОтдельныеСимволы.НомерСтроки
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
МояТаблица.НомерСтроки КАК НомерСтроки,
МояТаблица.Валюта КАК Валюта,
МояТаблица.ДатаОперации КАК ДатаОперации,
МояТаблица.МестоУчета КАК МестоУчета,
МояТаблица.Договор КАК Договор,
ВыходныеДанные.Хэш КАК Хэш,
МояТаблица.ВидДвижения КАК ВидДвижения
ИЗ
МояТаблица КАК МояТаблица
ЛЕВОЕ СОЕДИНЕНИЕ ВыходныеДанные КАК ВыходныеДанные
ПО (МояТаблица.НомерСтроки = ВыходныеДанные.НомерСтроки)
УПОРЯДОЧИТЬ ПО
Хэш,
ВидДвижения
АВТОУПОРЯДОЧИВАНИЕ
Показать
Использованы статьи Расчет хэш-функции в запросе и Выразить число как строку и дату как строку в запросе Поскольку в первом запросе используется функция "АВТОНОМЕРЗАПИСИ()", то требуется платформа 8.3.14. Если же номер строки уже есть в таблице, то требования к платформе понижаются.
Коротко об алгоритме: в первом запросе помещаем таблицу значений во временную таблицу. Во втором, каждое значение каждой колонки преобразуется к строке длинной 12 символов ( Для справочников используется код) и помещается в новую строку в колонку "Аргумент". Затем для набора аргументов каждого номера строки рассчитывается хэш.
А почему именно хэш, а не бухгалтерский остаток? Приход - расход, если отрицательный, тогда строка расхода снижается пока не уйдет в плюс?
Меньше вычислений чем в уме?