Каталог решений - СокрЛП() в запросе или что все-таки возможно получить с помощью запросов

СокрЛП() в запросе или что все-таки возможно получить с помощью запросов

СокрЛП() в запросе или что все-таки возможно получить с помощью запросов

В наличии

Показано, как в запросе можно удалить конечные и начальные пробелы у строки произвольной длины.
Разбиение строки на слова, решето Эратосфена и еще несколько примеров использования запросов 1С.

Категория:

Описание

Недавно понадобилось в запросе получить значение строковых кодов справочника без концевых пробелов. Как вы знаете, в языке запросов нет ничего похожего на функцию СокрЛП(), как же быть?

Можно, конечно, предварительно выполнить вспомогательный запрос, выгрузить его в таблицу значений, перебрать ее в цикле выполняя СокрЛП(), и затем передать обратно в нужный запрос в виде параметра (создать временную таблицу).

Или, если максимальная длина строки, как в случае кода справочника, фиксирована можно написать в запросе громоздкую конструкцию из вложенных конструкций ВЫБОР КОГДА…

Но это неинтересно. Благо на глаза попалась статья ildarovich-а //sale.itcity.ru/public/90367/. Оказалось, что с помощью временой таблицы с числами 0,1,2,3… можно получить много нетривиальных вещей в запросах.

Далее несколько примеров.

Сначала удаление начальных и конечных пробелов, аналог функции СокрЛП(). Заодно мы попутно получаем длину обрезанных строк.

Идея очень простая: ищем первый пробельный символ после которого идет не пробел (учитываем, что первый же символ может быть не пробелом) и последний не пробел после которого идет пробел.

Дополнительно тут используется, что выражение ПОДСТРОКА(СтрокаСПробелами, ЗначениеБольшеДлиныСтроки, 1) возвращает пустую строку, а при сравнении cтандарт SQL говорит, что строки, отличающиеся незначащими символами в хвосте не различаются. В языке запросов 1С сравнение происходит точно так-же. Т.е. для запроса «» = » «.

// Вспомогательный порождающий запрос
ВЫБРАТЬ 0 КАК Х ПОМЕСТИТЬ Регистр1 ОБЪЕДИНИТЬ ВЫБРАТЬ 1;
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК Старшие, Регистр1 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК Старшие, Регистр2 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК Старшие, Регистр4 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК Старшие, Регистр8 КАК Младшие;

// Создание таблицы с исходными строками, для тестирования
ВЫБРАТЬ "1 " КАК СтрокаСПробелами ПОМЕСТИТЬ ИсходнаяТаблица
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "22 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "333 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ " 4 4 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "5 555 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ " 666666 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "7777777 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ " 88888888 "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ "999999999";

// Непосредственно запрос обрезающий начальные и конечные пробелы и попутно получающий реальную длину строки
ВЫБРАТЬ
    СтрокаСПробелами КАК СтрокаСПробелами,
    МАКСИМУМ(Цикл_2.Х + 1) КАК ПоследнийЗначащийСимвол,
    МИНИМУМ(Цикл_1.Х + 1) КАК ПервыйЗначащийСимвол
ПОМЕСТИТЬ
    ПромежуточнаяТаблица
ИЗ
    ИсходнаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ
    Регистр16 КАК Цикл_1
ПО
    (ПОДСТРОКА(СтрокаСПробелами, Цикл_1.Х, 1) = " " И ПОДСТРОКА(СтрокаСПробелами, Цикл_1.Х + 1, 1) <> " ")
    ИЛИ (Цикл_1.Х = 0 И ПОДСТРОКА(СтрокаСПробелами, Цикл_1.Х + 1, 1) <> " ")
ЛЕВОЕ СОЕДИНЕНИЕ
    Регистр16 КАК Цикл_2
ПО
    ПОДСТРОКА(СтрокаСПробелами, Цикл_2.Х + 1, 1) <> " " И ПОДСТРОКА(СтрокаСПробелами, Цикл_2.Х + 2, 1) = " "
СГРУППИРОВАТЬ ПО
    СтрокаСПробелами
;

ВЫБРАТЬ
    ПОДСТРОКА(СтрокаСПробелами, ПервыйЗначащийСимвол, ПоследнийЗначащийСимвол - ПервыйЗначащийСимвол + 1) КАК СтрокаОбрезанная,
    ПоследнийЗначащийСимвол - ПервыйЗначащийСимвол + 1 КАК ДлинаСтроки
ИЗ
    ПромежуточнаяТаблица 

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

Здесь в качестве «пробельных» символов введена вспомогательная таблица с несколькими разделителями. Т.е. мы выполняем разложение строки не по пробелам, а по заданным разделителям.

// Вспомогательный порождающий запрос
ВЫБРАТЬ 0 КАК Х ПОМЕСТИТЬ Регистр1
ОБЪЕДИНИТЬ ВЫБРАТЬ 1;
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК Старшие, Регистр1 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК Старшие, Регистр2 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК Старшие, Регистр4 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК Старшие, Регистр8 КАК Младшие;

// Таблица разделителей слов
ВЫБРАТЬ " " КАК Разделитель ПОМЕСТИТЬ Разделители
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ " "
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ";"
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ ",";

// Создание таблицы с исходной строкой для разложения
ВЫБРАТЬ "Съешь еще этих французских булок" КАК СтрокаДляРазложения ПОМЕСТИТЬ ИсходнаяТаблица;

// Получаем границы слов
ВЫБРАТЬ
	Цикл_1.Х + 1 КАК НачалоСлова,
    МИНИМУМ(Цикл_2.Х + 1) КАК КонецСлова
ПОМЕСТИТЬ
    ГраницыСлов
ИЗ
    ИсходнаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ
    Регистр16 КАК Цикл_1
ПО
    (ПОДСТРОКА(СтрокаДляРазложения, Цикл_1.Х, 1) В (ВЫБРАТЬ Разделитель ИЗ Разделители) ИЛИ Цикл_1.Х = 0)
    И ПОДСТРОКА(СтрокаДляРазложения, Цикл_1.Х + 1, 1) НЕ В (ВЫБРАТЬ Разделитель ИЗ Разделители)
ЛЕВОЕ СОЕДИНЕНИЕ
    Регистр16 КАК Цикл_2
ПО
    ПОДСТРОКА(СтрокаДляРазложения, Цикл_2.Х + 1, 1) НЕ В (ВЫБРАТЬ Разделитель ИЗ Разделители)
    И ПОДСТРОКА(СтрокаДляРазложения, Цикл_2.Х + 2, 1) В (ВЫБРАТЬ Разделитель ИЗ Разделители)
    И Цикл_2.Х >= Цикл_1.Х
СГРУППИРОВАТЬ ПО
    Цикл_1.Х
;

// Исходя из полученных границ слов выполняем разложение строки
ВЫБРАТЬ
	ПОДСТРОКА(СтрокаДляРазложения, НачалоСлова, КонецСлова - НачалоСлова + 1)
ИЗ
	ИсходнаяТаблица, ГраницыСлов

Решето Эратосфена, выдающее таблицу простых чисел

// Вспомогательный порождающий запрос
ВЫБРАТЬ 0 КАК Х ПОМЕСТИТЬ Регистр1 ОБЪЕДИНИТЬ ВЫБРАТЬ 1;
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК Старшие, Регистр1 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК Старшие, Регистр2 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК Старшие, Регистр4 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК Старшие, Регистр8 КАК Младшие;

// Решето Эратосфена, на выходе получаем таблицу всех простых чисел меньших 65536 + 2
ВЫБРАТЬ Регистр4.Х + 2 КАК Х ПОМЕСТИТЬ Решето4
ИЗ Регистр4 ЛЕВОЕ СОЕДИНЕНИЕ Регистр2
ПО Регистр4.Х > Регистр2.Х + 1 И (Регистр4.Х + 2) / (Регистр2.Х + 2) = ВЫРАЗИТЬ((Регистр4.Х + 2) / (Регистр2.Х + 2) КАК Число(32))
ГДЕ Регистр2.Х ЕСТЬ NULL
;

ВЫБРАТЬ Регистр8.Х + 2 КАК Х ПОМЕСТИТЬ Решето8
ИЗ Регистр8 ЛЕВОЕ СОЕДИНЕНИЕ Решето4
ПО Регистр8.Х + 1 > Решето4.Х И (Регистр8.Х + 2) / Решето4.Х = ВЫРАЗИТЬ((Регистр8.Х + 2) / Решето4.Х КАК Число(32))
ГДЕ Решето4.Х ЕСТЬ NULL
;

ВЫБРАТЬ Регистр16.Х + 2 ПростоеЧисло
ИЗ Регистр16 ЛЕВОЕ СОЕДИНЕНИЕ Решето8
ПО Регистр16.Х + 1 > Решето8.Х И (Регистр16.Х + 2) / Решето8.Х = ВЫРАЗИТЬ((Регистр16.Х + 2) / Решето8.Х КАК Число(32))
ГДЕ Решето8.Х ЕСТЬ NULL

Степени двойки до 2^106, большие степени не помещаются в 32 знака (не разряда!) числа, которыми оперирует 1С

ВЫБРАТЬ 0 КАК Степень, 1 КАК Результат ПОМЕСТИТЬ Регистр1
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1, 2;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК ПервыйСомножитель, Регистр1 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК ПервыйСомножитель, Регистр2 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК ПервыйСомножитель, Регистр4 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК ПервыйСомножитель, Регистр8 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр32
ИЗ Регистр16 КАК ПервыйСомножитель, Регистр16 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ПОМЕСТИТЬ Регистр64
ИЗ Регистр32 КАК ПервыйСомножитель, Регистр32 КАК ВторойСомножитель;

ВЫБРАТЬ РАЗЛИЧНЫЕ
	ПервыйСомножитель.Степень + ВторойСомножитель.Степень КАК Степень,
	ПервыйСомножитель.Результат * ВторойСомножитель.Результат КАК Результат
ИЗ Регистр64 КАК ПервыйСомножитель, Регистр64 КАК ВторойСомножитель
ГДЕ ПервыйСомножитель.Степень + ВторойСомножитель.Степень < 107

Запрос, выполняющий точное вычисление квадратного корня числа в диапазоне 0 — 1 048 576, развитие запроса из статьи ildarovich-а (см. ссылку в начале), который вычислял целое значение квадратного корня.

// Вспомогательный порождающий запрос
ВЫБРАТЬ 0 КАК Х ПОМЕСТИТЬ Регистр1 ОБЪЕДИНИТЬ ВЫБРАТЬ 1;
ВЫБРАТЬ Младшие.Х + 2 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр2
ИЗ Регистр1 КАК Старшие, Регистр1 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 4 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр4
ИЗ Регистр2 КАК Старшие, Регистр2 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 16 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр8
ИЗ Регистр4 КАК Старшие, Регистр4 КАК Младшие;
ВЫБРАТЬ Младшие.Х + 256 * Старшие.Х КАК Х ПОМЕСТИТЬ Регистр16
ИЗ Регистр8 КАК Старшие, Регистр8 КАК Младшие;

// Для проверки создается таблица с различными значениями аргумента
ВЫБРАТЬ 123456 КАК У ПОМЕСТИТЬ Аргументы
ОБЪЕДИНИТЬ ВЫБРАТЬ 555555
ОБЪЕДИНИТЬ ВЫБРАТЬ 987654;

// Вычисляем сначала целую часть (решение ildarovich-а)
ВЫБРАТЬ У КАК У, МАКСИМУМ(Х) КАК Квадратный_корень_У, У - МАКСИМУМ(Х) * МАКСИМУМ(Х) КАК Дельта
ПОМЕСТИТЬ ЦелаяЧастьКорня
ИЗ Аргументы ЛЕВОЕ СОЕДИНЕНИЕ Регистр16 ПО (Х * Х <= У)
СГРУППИРОВАТЬ ПО У;

// Продолжение запроса, вычисляющее дополнительные знаки после запятой

// Вспомогательная таблица для уменьшения количества делений
ВЫБРАТЬ Х КАК Х, Х/65536 КАК Дробь ПОМЕСТИТЬ Дроби16 ИЗ Регистр16;

// Теперь уточним значение с точностью до 1/65536
ВЫБРАТЬ У КАК У, Квадратный_корень_У + МАКСИМУМ(Дробь) КАК Квадратный_корень_У, У - (Квадратный_корень_У + МАКСИМУМ(Дробь)) * (Квадратный_корень_У + МАКСИМУМ(Дробь)) КАК Дельта
ПОМЕСТИТЬ Приближение1
ИЗ ЦелаяЧастьКорня ЛЕВОЕ СОЕДИНЕНИЕ Дроби16 ПО ((Квадратный_корень_У + Дробь) * (Квадратный_корень_У + Дробь) <= У)
СГРУППИРОВАТЬ ПО У, Квадратный_корень_У;

// Вспомогательная таблица для уменьшения количества делений
ВЫБРАТЬ Х КАК Х, Дробь/65536 КАК Дробь ПОМЕСТИТЬ Дроби32 ИЗ Дроби16;

// С точностью до 1/4294967296
ВЫБРАТЬ У КАК У, Квадратный_корень_У + МАКСИМУМ(Дробь) КАК Квадратный_корень_У, У - (Квадратный_корень_У + МАКСИМУМ(Дробь)) * (Квадратный_корень_У + МАКСИМУМ(Дробь)) КАК Дельта
ПОМЕСТИТЬ Приближение2
ИЗ Приближение1 ЛЕВОЕ СОЕДИНЕНИЕ Дроби32 ПО ((Квадратный_корень_У + Дробь) * (Квадратный_корень_У + Дробь) <= У)
СГРУППИРОВАТЬ ПО У, Квадратный_корень_У;

// Вспомогательная таблица для уменьшения количества делений
ВЫБРАТЬ Х КАК Х, Дробь/65536 КАК Дробь ПОМЕСТИТЬ Дроби48 ИЗ Дроби32;

// С точностью до 1/281474976710656
ВЫБРАТЬ У КАК У, Квадратный_корень_У + МАКСИМУМ(Дробь) КАК Квадратный_корень_У, У - (Квадратный_корень_У + МАКСИМУМ(Дробь)) * (Квадратный_корень_У + МАКСИМУМ(Дробь)) КАК Дельта
ПОМЕСТИТЬ Приближение3
ИЗ Приближение2 ЛЕВОЕ СОЕДИНЕНИЕ Дроби48 ПО ((Квадратный_корень_У + Дробь) * (Квадратный_корень_У + Дробь) <= У)
СГРУППИРОВАТЬ ПО У, Квадратный_корень_У;

// Вспомогательная таблица для уменьшения количества делений
ВЫБРАТЬ Х КАК Х, Дробь/65536 КАК Дробь ПОМЕСТИТЬ Дроби64 ИЗ Дроби48;

// С точностью до 1/18446744073709551616
ВЫБРАТЬ У КАК У, Квадратный_корень_У + МАКСИМУМ(Дробь) КАК Квадратный_корень_У, У - (Квадратный_корень_У + МАКСИМУМ(Дробь)) * (Квадратный_корень_У + МАКСИМУМ(Дробь)) КАК Дельта
ИЗ Приближение3 ЛЕВОЕ СОЕДИНЕНИЕ Дроби64 ПО ((Квадратный_корень_У + Дробь) * (Квадратный_корень_У + Дробь) <= У)
СГРУППИРОВАТЬ ПО У, Квадратный_корень_У
 
has been added to your cart:
Оформление заказа