1. Используемый способ вычисления значения хэш-функции
Для расчета значения хэш-функции строковых значений может использоваться следующая формула
h(S) = S[0] + S[1] * P + S[2] * P^2 + S[3] * P^3 + ... + S[N] * P^N, где P - некоторое простое число, например, 31.
То есть, значение хэш-функции является суммой произведения кодов символов строки на члены степенного ряда 1, 31, 31^2, 31^3, 31^4 и так далее. При этом все расчеты выполняются по модулю 2^32, то есть при вычислениях отбрасываются все двоичные разряды, старше тридцать второго. Такой способ расчета хэш-функции приводится, например, в статье "Алгоритмы хэширования в задачах на строки".
Таблица степенного ряда, содержащая две колонки: "Позиция" и "ЧленРяда" будет иметь вид:
Позиция | ЧленРяда |
1 | 1 |
2 | 31 |
3 | 961 |
4 | 29791 |
5 | 923521 |
6 | 28629151 |
7 | 887503681 |
8 |
1742810335 |
9 |
2487512833 |
10 |
4098453791 |
11 | 2498015937 |
12 | 129082719 |
... | ... |
Интересно, что в таблице степенного ряда элемент в 12-ой позиции оказался меньше элемента в 11-й позиции, который, в свою очередь, оказался меньше элемента в 10-й позиции за счет расчета степени в кольце 2^32.
2. Текст основного запроса
Если таблица с исходными данными имеет две колонки: колонку "НомерСтроки" и строковую колонку "Аргумент", а таблица степенного ряда уже построена, то запрос для расчета Хэш-функции будет иметь вид:
ВЫБРАТЬ
Данные.НомерСтроки,
ПОДСТРОКА(Данные.Аргумент, Ряд.Позиция, 1) КАК Символ,
Ряд.ЧленРяда
ПОМЕСТИТЬ ОтдельныеСимволы
ИЗ
ИсходныеДанные КАК Данные,
СтепеннойРяд КАК Ряд
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Символы.НомерСтроки,
СУММА(Символы.ЧленРяда * Таблица.Код) КАК СуммаПроизведений
ПОМЕСТИТЬ СырыеДанные
ИЗ
ОтдельныеСимволы КАК Символы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ КодоваяТаблица КАК Таблица
ПО Символы.Символ = Таблица.Символ
И (Символы.Символ ПОДОБНО Таблица.Символ)
СГРУППИРОВАТЬ ПО
Символы.НомерСтроки
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Данные.НомерСтроки,
Данные.СуммаПроизведений - ((ВЫРАЗИТЬ(Данные.СуммаПроизведений / 4294967296 + 0.5 КАК ЧИСЛО(20, 0))) - 1) * 4294967296 КАК Хэш
ПОМЕСТИТЬ ВыходныеДанные
ИЗ
СырыеДанные КАК Данные
Совместное использование в условии связи условий "равно" и "подобно" требуется, чтобы различать строчные и прописные буквы, не теряя при этом в скорости соединения по индексу кодовой таблицы.
3. Запросы для формирования вспомогательных таблиц
В основном запросе, кроме таблицы степенного ряда, используется таблица "КодоваяТаблица", сопоставляющая каждому используемому символу его код:
Символ | Код |
... | ... |
A | 65 |
B | 66 |
... | ... |
Чтобы не вводить полную таблицу юникода, предлагается ограничиться только символами, имеющимися в таблице windows-1251. Этот набор символов получается следующей функцией:
Функция НаборСимволов(КодировкаТекста = "windows-1251", Ответ = "")
Для КодСимвола = 1 По 255 Цикл
Ответ = Ответ + Символ(КодСимвола)
КонецЦикла;
ТекстовыйДокумент = Новый ТекстовыйДокумент;
ТекстовыйДокумент.УстановитьТекст(Ответ);
ПутьКФайлу = ПолучитьИмяВременногоФайла();
ТекстовыйДокумент.Записать(ПутьКФайлу, "ISO-8859-1", "");
ТекстовыйДокумент.Прочитать(ПутьКФайлу, КодировкаТекста, "");
Ответ = ТекстовыйДокумент.ПолучитьТекст();
Возврат Ответ
КонецФункции
Следующий запрос осуществляет ввод этого набора символов во временную таблицу "КодоваяТаблица". В результате указанная таблица фактически является таблицей перекодировки символов юникода в коды ascii. Те символы юникода, которые не попали в таблицу перекодировки, при расчете хэш-функции учтены не будут.
ВЫБРАТЬ
ПОДСТРОКА(&НаборСимволов, Ряд.Позиция, 1) КАК Символ,
Ряд.Позиция КАК Код
ПОМЕСТИТЬ КодоваяТаблица
ИЗ
НачалоРяда КАК Ряд
ИНДЕКСИРОВАТЬ ПО
Символ
Для расчета степенного ряда используется один начальный запрос
ВЫБРАТЬ
1 КАК Позиция,
1 КАК ЧленРяда,
ЛОЖЬ КАК Край
ПОМЕСТИТЬ НачалоРяда
ОБЪЕДИНИТЬ
ВЫБРАТЬ
2,
31,
ИСТИНА
и несколько повторений запроса следующего вида:
ВЫБРАТЬ
Ряд.Позиция,
Ряд.ЧленРяда,
ЛОЖЬ КАК Край
ПОМЕСТИТЬ ПродолженныйРяд
ИЗ
НачалоРяда КАК Ряд
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Ряд.Позиция + Грань.Позиция,
Ряд.ЧленРяда * Грань.ЧленРяда * 31,
Ряд.Край
ИЗ
НачалоРяда КАК Ряд
ВНУТРЕННЕЕ СОЕДИНЕНИЕ НачалоРяда КАК Грань
ПО (Грань.Край)
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ НачалоРяда
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Ряд.Позиция,
Ряд.ЧленРяда - ((ВЫРАЗИТЬ(Ряд.ЧленРяда / 4294967296 + 0.5 КАК ЧИСЛО(20, 0))) - 1) * 4294967296 КАК ЧленРяда,
Ряд.Край
ПОМЕСТИТЬ НачалоРяда
ИЗ
ПродолженныйРяд КАК Ряд
;
////////////////////////////////////////////////////////////////////////////////
УНИЧТОЖИТЬ ПродолженныйРяд
На каждом повторении степенной ряд увеличивается вдвое. Первый запрос удлинняет ряд, а второй запрос в пакете отбрасывает лишние биты старше тридцать второго. Необходимое минимальное число повторений - восемь. Это дает возможность "развернуть" кодовую таблицу из набора симворов и расчитать хэш строки длиной до 256. Если длина строки больше, то нужно добавить еще несколько повторений.
После формирования степенного ряда путем последовательных удвоений, он обрезается до точной длины строки в следующем запросе:
ВЫБРАТЬ
Ряд.Позиция,
Ряд.ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд
ИЗ
НачалоРяда КАК Ряд
ГДЕ
Ряд.Позиция <= &ДлинаСтроки
4. Результаты испытаний
По аналогии со статьей "Несколько простых хеш-функций и их свойства" вычислена частота повторения значений в отдельных байтах получаемого значения хэш-функции. Для этого рассчитан миллион значений хэш-функции для случайных строк длиной 10 байтов, составленных из заглавных символов латинского алфавита от A до Z. Соответствующие графики приведены на Фиг.1.
Частота0 на графике обозначает частоту повторения значений нулевого байта, Частота 1 - первого и так далее.
Видно, что байты с нулевого по второй распределены практически равномерно. Исключение составляет третий байт, в поведении которого наблюдаются нежелательные закономерности. Впрочем, для практических целей это приемлемо. Действительно больших выбросов на графиках нет. Тем более, скорее всего, наличие закономерностей объясняется небольшим диапазоном использованных символов в исходной строке.
Запрос показывает вполне приемлемую скорость расчетов. На расчет миллиона хэшей для строк из 10-ти символов на хорошем компьютере уходит примерно 100 секунд. Следовательно, один символ отнимает примерно 0.01 миллисекунды. Исходя из этого можно определить требуемое время расчета хэшей для любой исходной таблицы. Если сравнить быстродействие предлагаемого метода расчета в запросе и метода расчета значения хэш-функции в коде, описываемого в статье "Простая и быстрая хэш функция (hash) средствами 1С (оптимизированный вариант)", то получается, что предлагаемый метод на строках длинной 1222 символа показывает быстродействие примерно 12440 хэшей в минуту, то есть его скорость примерно в два раза ниже расчета хэш-функции в коде.
При необходимости, предложенную схему построения запроса, рассчитывающую хэш-функцию, можно модифицировать.Можно увеличить разрядность значения хэш-функции. Можно изменить основание степенного ряда: подойдет простое число, примерно соответствующее количеству различных символов в строке: 37, 53 и так далее. Можно увеличить кодовую таблицу, добавив весь юникод или реально встречающиеся символы. А также, во многих задачах можно не отбрасывать лишние биты после суммирования произведений. Также существует несколько других вариантов записи основного запроса: с использованием вложенных запросов или с одновременным соединением таблиц исходных данных, таблицы степенного ряда и кодовой таблицы, отличающихся более компактной записью. Приведенный вариант выбран из-за большей наглядности и стабильной скорости выполнения.
Использованная формула не позволяет применять данный метод для задач криптогафии. Это хорошо показано в статье "Лжеотождествление электровиолончели". Там предлагается не слишком сложный метод подбора строк с нулевым значением хэш-функции.
Тем не менее, круг задач, решаемый с использованием предлагаемого приема, может быть довольно широким.
Пример 1. Разбиение множества элементов номенклатуры на классы, имеющие одинаковое сочетание значений свойств.
В конфигурации "1С: Управление торговлей" редакции 10.3 длина кода значения свойства ограничена девятью знаками, а код состоит из одних цифр. С учетом этого поставленную задачу решает следующий запрос:
ВЫБРАТЬ 1 Позиция, 1 ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд
ОБЪЕДИНИТЬ ВЫБРАТЬ 2, 31
ОБЪЕДИНИТЬ ВЫБРАТЬ 3, 961
ОБЪЕДИНИТЬ ВЫБРАТЬ 4, 29791
ОБЪЕДИНИТЬ ВЫБРАТЬ 5, 923521
ОБЪЕДИНИТЬ ВЫБРАТЬ 6, 28629151
ОБЪЕДИНИТЬ ВЫБРАТЬ 7, 887503681
ОБЪЕДИНИТЬ ВЫБРАТЬ 8, 1742810335
ОБЪЕДИНИТЬ ВЫБРАТЬ 9, 2487512833
ОБЪЕДИНИТЬ ВЫБРАТЬ 10, 4098453791
;
ВЫБРАТЬ ПОДСТРОКА("0123456789", Позиция, 1) КАК Символ, Позиция КАК Код
ПОМЕСТИТЬ КодоваяТаблица
ИЗ СтепеннойРяд
ИНДЕКСИРОВАТЬ ПО Символ
;
ВЫБРАТЬ Объект КАК Ссылка, Значение.Код КАК Аргумент
ПОМЕСТИТЬ ИсходныеДанные
ИЗ РегистрСведений.ЗначенияСвойствОбъектов
ГДЕ Объект ССЫЛКА Справочник.Номенклатура
;
ВЫБРАТЬ Ссылка, ПОДСТРОКА(Аргумент, Позиция, 1) КАК СимволКода, ЧленРяда
ПОМЕСТИТЬ ОтдельныеСимволы
ИЗ ИсходныеДанные, СтепеннойРяд
;
ВЫБРАТЬ Ссылка, СУММА(ЧленРяда * Код) КАК Хэш
ПОМЕСТИТЬ ВыходныеДанные
ИЗ ОтдельныеСимволы ВНУТРЕННЕЕ СОЕДИНЕНИЕ КодоваяТаблица
ПО СимволКода = Символ
СГРУППИРОВАТЬ ПО Ссылка
;
ВЫБРАТЬ Ссылка
ИЗ ВыходныеДанные
ИТОГИ ПО Хэш
Запрос будет работать в любой универсальной консоли запросов. Обход результата запроса по группировкам соответствует обходу номенклатуры по классам эквивалентности с точки зрения набора значений свойств. Заменив в одном месте наименование справочника, тем же запросом можно классифицировать контрагентов, сотрудников и другие объекты предметной области, имеющие заданные наборы свойств.
Запрос компактизирован для улучшения обзорности и слегка упрощен по сравнению с запросом для общего случая: степенной ряд задается непосредственно, кодовая таблица состоит из одних цифр и убрано ненужное в данном случае отбрасывание старших разрядов. В качестве хэша набора значений свойств использована арифметическая сумма хэшей кодов значений свойств, хотя в идеале хэши лучше складывать поразрядным XOR.
Пример 2. Определение ТОП-5 состава товаров в накладных реализации
Данная задача также решается получением уникального числа для каждого набора товаров как суммы хэшей кодов номенклатуры в табличной части "Товары". Выбираются топ-5 хэшей, соответствующих наибольшему количеству накладных. Далее определяется состав хит-наборов. Учитывается, что код номенклатуры является строкой длиной 11 символов и состоит из одних цифр. В результате весь необходимый текст запроса, решающего поставленную задачу, будет иметь вид:
ВЫБРАТЬ 1 Позиция, 1 ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд
ОБЪЕДИНИТЬ ВЫБРАТЬ 2, 31
ОБЪЕДИНИТЬ ВЫБРАТЬ 3, 961
ОБЪЕДИНИТЬ ВЫБРАТЬ 4, 29791
ОБЪЕДИНИТЬ ВЫБРАТЬ 5, 923521
ОБЪЕДИНИТЬ ВЫБРАТЬ 6, 28629151
ОБЪЕДИНИТЬ ВЫБРАТЬ 7, 887503681
ОБЪЕДИНИТЬ ВЫБРАТЬ 8, 1742810335
ОБЪЕДИНИТЬ ВЫБРАТЬ 9, 2487512833
ОБЪЕДИНИТЬ ВЫБРАТЬ 10, 4098453791
ОБЪЕДИНИТЬ ВЫБРАТЬ 11, 2498015937
;
ВЫБРАТЬ ПОДСТРОКА("0123456789", Позиция, 1) КАК Символ, Позиция КАК Код
ПОМЕСТИТЬ КодоваяТаблица
ИЗ СтепеннойРяд
ИНДЕКСИРОВАТЬ ПО Символ
;
ВЫБРАТЬ Ссылка, Номенклатура.Код КАК Аргумент
ПОМЕСТИТЬ ИсходныеДанные
ИЗ Документ.РеализацияТоваровУслуг.Товары
ГДЕ Ссылка.Организация = &Организация И Ссылка.Дата МЕЖДУ &Дата1 И &Дата2
;
ВЫБРАТЬ Ссылка, ПОДСТРОКА(Аргумент, Позиция, 1) КАК СимволКода, ЧленРяда
ПОМЕСТИТЬ ОтдельныеСимволы
ИЗ ИсходныеДанные, СтепеннойРяд
;
ВЫБРАТЬ Ссылка, СУММА(ЧленРяда * Код) КАК Хэш
ПОМЕСТИТЬ ВыходныеДанные
ИЗ ОтдельныеСимволы ВНУТРЕННЕЕ СОЕДИНЕНИЕ КодоваяТаблица
ПО СимволКода = Символ И СимволКода ПОДОБНО Символ
СГРУППИРОВАТЬ ПО Ссылка
;
ВЫБРАТЬ Первые 5 Хэш, Количество(*) КАК Частота
ПОМЕСТИТЬ ХитовыеХэши
ИЗ ВыходныеДанные
СГРУППИРОВАТЬ ПО Хэш
УПОРЯДОЧИТЬ ПО Частота УБЫВ
;
ВЫБРАТЬ РАЗЛИЧНЫЕ Номенклатура, Частота
ИЗ ХитовыеХэши
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВыходныеДанные ПО ХитовыеХэши.Хэш = ВыходныеДанные.Хэш
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг.Товары КАК Товары ПО ВыходныеДанные.Ссылка = Товары.Ссылка
УПОРЯДОЧИТЬ ПО Частота УБЫВ
ИТОГИ ПО ХитовыеХэши.Хэш
Еще одна довольно специфическая задача, в рамках решения которой, собственно, и был разработан данный метод, будет приведена в отдельной публикации.
Пример 3. "ВЫБРАТЬ СЛУЧАЙНЫЕ"
Не так часто, но все же встречается задачи, когда запрос должен вернуть не определенные, а некоторые случайным образом выбранные записи какой-либо таблицы. Если имеется конструкция "ВЫБРАТЬ РАЗЛИЧНЫЕ", "ВЫБРАТЬ ПЕРВЫЕ", то отражением требования этой задачи было бы наличие в языке запросов конструкции "ВЫБРАТЬ СЛУЧАЙНЫЕ". И хотя такой конструкции нет, ее можно смоделировать. Например, присоединив (динамически в запросе) к коду элементу справочника строку текущей даты (вместе с временем) и рассчитав хэш полученной строки, можно получить некоторое псевдослучайное число. Если отсортировать по этому числу справочник и выбрать нужное число первых элементов, то выбор будет малопредсказуемым, то есть фактически случайным. Из соображений эффективности можно сделать еще проще - добавлять текущее время (в секундах) с начала времен к получаемой сумме произведений.
Такой подход использован в следующем запросе
ВЫБРАТЬ Ссылка, Код КАК Аргумент
ПОМЕСТИТЬ ИсходныеДанные
ИЗ Справочник.Номенклатура
ГДЕ НЕ ЭтоГруппа
;
ВЫБРАТЬ 1 Позиция, 1 КАК ЧленРяда
ПОМЕСТИТЬ СтепеннойРяд
ОБЪЕДИНИТЬ ВЫБРАТЬ 2, 31
ОБЪЕДИНИТЬ ВЫБРАТЬ 3, 961
ОБЪЕДИНИТЬ ВЫБРАТЬ 4, 29791
ОБЪЕДИНИТЬ ВЫБРАТЬ 5, 923521
ОБЪЕДИНИТЬ ВЫБРАТЬ 6, 28629151
ОБЪЕДИНИТЬ ВЫБРАТЬ 7, 887503681
ОБЪЕДИНИТЬ ВЫБРАТЬ 8, 1742810335
ОБЪЕДИНИТЬ ВЫБРАТЬ 9, 2487512833
ОБЪЕДИНИТЬ ВЫБРАТЬ 10, 4098453791
ОБЪЕДИНИТЬ ВЫБРАТЬ 11, 2498015937
;
ВЫБРАТЬ Ссылка, РАЗНОСТЬДАТ(ДАТАВРЕМЯ(2015, 1, 1), &ТекущаяДата, СЕКУНДА) * 129082719 +
СУММА(ЧленРяда * ВЫБОР ПОДСТРОКА(Аргумент, Позиция, 1) КОГДА ""0"" ТОГДА 1 КОГДА ""1"" ТОГДА 2 КОГДА ""2"" ТОГДА 3 КОГДА ""3"" ТОГДА 4
КОГДА ""4"" ТОГДА 5 КОГДА ""5"" ТОГДА 6 КОГДА ""6"" ТОГДА 7 КОГДА ""7"" ТОГДА 8 КОГДА ""8"" ТОГДА 9 КОГДА ""9"" ТОГДА 10 ИНАЧЕ 0 КОНЕЦ) КАК Сумма
ПОМЕСТИТЬ СырыеДанные
ИЗ ИсходныеДанные, СтепеннойРяд
СГРУППИРОВАТЬ ПО Ссылка
;
ВЫБРАТЬ ПЕРВЫЕ 5 Ссылка КАК Элемент
ИЗ СырыеДанные
УПОРЯДОЧИТЬ ПО Сумма - ((ВЫРАЗИТЬ(Сумма / 16777216 + 0.5 КАК ЧИСЛО(20, 0))) - 1) * 16777216
В отличие от предыдущих запросов, здесь не используется кодовая таблица. Если в коде справочника использованы одни цифры, то код цифр быстрее получается с использованием оператора "ВЫБОР". Также использованы только младшие три байта хэш функции, имеющие более равномерное распределение. Заменив наименование справочника, можно выбирать случайных контрагентов, сотрудников и так далее.
Для достижения максимального быстродействия, учитывая небольшую фиксированную длину кода элемента справочника можно записать сумму в одно выражение (инлайн). Также можно снизить затраты на сортировку, предварительно отобрав строки в соответствиями с идеей статьи Selecting Rows Randomly from a Large Table. В итоге получается следующий быстрый запрос:
ВЫБРАТЬ
Номенклатура.Ссылка,
Номенклатура.Код КАК Аргумент
ПОМЕСТИТЬ ИсходныеДанные
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
НЕ Номенклатура.ЭтоГруппа
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ИсходныеДанные.Ссылка,
РАЗНОСТЬДАТ(ДАТАВРЕМЯ(2015, 1, 1), &ТекущаяДата, СЕКУНДА) * 129082719 + 1 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 1, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 31 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 2, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 961 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 3, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 29791 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 4, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 923521 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 5, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 28629151 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 6, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 887503681 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 7, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 1742810335 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 8, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 2487512833 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 9, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 4098453791 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 10, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ + 2498015937 * ВЫБОР ПОДСТРОКА(ИсходныеДанные.Аргумент, 11, 1)
КОГДА "0"
ТОГДА 1
КОГДА "1"
ТОГДА 2
КОГДА "2"
ТОГДА 3
КОГДА "3"
ТОГДА 4
КОГДА "4"
ТОГДА 5
КОГДА "5"
ТОГДА 6
КОГДА "6"
ТОГДА 7
КОГДА "7"
ТОГДА 8
КОГДА "8"
ТОГДА 9
КОГДА "9"
ТОГДА 10
ИНАЧЕ 0
КОНЕЦ КАК Сумма
ПОМЕСТИТЬ СырыеДанные
ИЗ
ИсходныеДанные КАК ИсходныеДанные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ ПЕРВЫЕ 5
Данные.Ссылка КАК Элемент
ИЗ
(ВЫБРАТЬ
СырыеДанные.Ссылка КАК Ссылка,
СырыеДанные.Сумма - ((ВЫРАЗИТЬ(СырыеДанные.Сумма / 16777216 + 0.5 КАК ЧИСЛО(20, 0))) - 1) * 16777216 КАК Сумма
ИЗ
СырыеДанные КАК СырыеДанные) КАК Данные,
(ВЫБРАТЬ
КОЛИЧЕСТВО(*) КАК Количество
ИЗ
ИсходныеДанные КАК ИсходныеДанные) КАК ВложенныйЗапрос
ГДЕ
Данные.Сумма < 5 * 2 * 16777216 / ВложенныйЗапрос.Количество
УПОРЯДОЧИТЬ ПО
Данные.Сумма