Имя: Пароль:
1C
1С v8
Избежать запрос в цикле
0 Oleg37701
 
13.12.22
10:27
Коллеги, подскажите, может, кто сталкивался. Есть табличная часть - запрашиваемая номенклатура (строка) и количество(число)

Пользователи вводят строкой название запрашиваемой номенклатуры. Далее нужно в специальном регистре искать в нескольких колонка это наименование подобно тому, как это происходит при условии "содержит"

Например, пользователь вбил ААА31 Паста Блендамет.

В регистре есть строки:

Паста Блендамет ААА31
ААА31 Паста Блендамет
Паста Блендамет ААА31 со кусом клубники

Эти все строки он должен найти, запрос ПОДОБНо в лоб, естсенно не отрабатывает.

Пришла в голову мысль, для каждой строки ТЧ формировать свой текст Запроса с условием:
ПОДОБНО %Паста%
И ПОДОБНО %АА3%
И ПОДОБНО %БЛЕНДАМЕТ%

Искать нужно по нескольким колонкам.

Можно ли избежать запрос в цикле? Есть более изящное решение?
1 Kassern
 
13.12.22
10:29
(0) чем вас полнотекстовый поиск не устроил?
2 Oleg37701
 
13.12.22
10:29
(1) Выключен.
3 rbcvg
 
13.12.22
10:30
"Есть более изящное решение?" - навести порядок в регистре.
4 Oleg37701
 
13.12.22
10:31
(3) Ну, приходится работать с тем, что есть. Данные загружаются из внешнего источника от поставщиков. Постоянно править нет возможности.
5 Kassern
 
13.12.22
10:32
(2) Так может его просто включить, проиндексировать, настроить рег задания и не ломать голову?
6 Oleg37701
 
13.12.22
10:33
(5) Полнотекстовый поиск выключен был до меня. о словам человека: для улучшения производительности. Включать отказались.
7 Garykom
 
гуру
13.12.22
10:35
(6) Объясни что данная задача требует его включения и постоянной актуализации
8 Kassern
 
13.12.22
10:36
(6) просто нужно уметь его готовить)
Попробуйте на тестовой среде его погонять и почитайте за него, как правильно настроить. Это имхо будет лучше чем вы напишите, так как работает на уровне платформы
9 Oleg37701
 
13.12.22
10:37
(8) Понял, спасибо большое!
10 Oleg37701
 
13.12.22
10:39
(7) Рассматривал этот вариант на крайний случай, понял, спасибо большое. Пойду разговаривать.
11 Garykom
 
гуру
13.12.22
10:40
Учти что полнотекстовый будет выдавать не всегда адекватные результаты
Ибо как понял тут поиск аналогов по характеристикам
Надо разделять на них, хранить их в стандартизированном виде в разных полях и искать/подбирать уже по ним
12 Garykom
 
гуру
13.12.22
10:41
Паста Блендамет ААА31
ААА31 Паста Блендамет
Паста Блендамет ААА31 со кусом клубники

Тип: Паста
Марка: Блендамет
Артикул: ААА31
Свойство: со кусом клубники
13 Oleg37701
 
13.12.22
10:42
(11) (12) Понял, спасибо большое, буду тестировать.
14 hockeyist
 
13.12.22
10:42
Не понял. Почему это должно быть в цикле?

ПОДОБНО %Паста%
И ПОДОБНО %АА3%
И ПОДОБНО %БЛЕНДАМЕТ%

Без цикла разве не сработает?
15 Garykom
 
гуру
13.12.22
10:43
(13) И да даже крупняк (разные там яндексы/озоны и прочие али) не всегда в это смогли
Хотя узкоспециализированные делают почти идеально, например ДНС
16 Oleg37701
 
13.12.22
10:44
(14) Дело в том, что может быть несколько строк в табличной части и у каждой строки свое запрашиваемое наименование.
17 Oleg37701
 
13.12.22
10:45
(14) То есть, чтобы обойти всю табличную часть, условия подобно должны быть динамичными.
18 Oleg37701
 
13.12.22
10:47
(14) И вот как раз цикл нужен, чтобы обойти все строки тч
19 hockeyist
 
13.12.22
11:09
"Например, пользователь вбил ААА31 Паста Блендамет"
Он это для каждой строки отдельно "вбивает"? Тогда цикла по любому не избежать.
20 Oleg37701
 
13.12.22
11:16
(19) Да, для каждой строки в табличную часть. Ну вот про цикл и я подумал. Ребята выше посоветовали уговорить включить полнотекстовый поиск.
21 hockeyist
 
13.12.22
11:19
(20) И что ты подумал "про цикл"?
22 Oleg37701
 
13.12.22
11:24
(21) Запрос в цикле.
23 Garykom
 
гуру
13.12.22
11:26
(20) если количество ПОДОБНО всегда одинаково для строк то можно запрос без цикла
ну или группируй с одинаковым кол-вом ПОДОБНО и пакетами
24 Oleg37701
 
13.12.22
11:28
(23) Нет, может быть разное количество слов. Вот сейчас, как вы и рекомендовали, курю полнотекстовый поиск и стандартизацию хранения в разных полях.
25 SleepyHead
 
гуру
13.12.22
11:31
(20) Собери текст запроса в цикле и выполни  один раз
26 Oleg37701
 
13.12.22
11:36
(25) Вы уверены что это сработает?

Предположим у нас 25 строк в табличной части, у каждой строки по 3 -4 слова.

Я все это соберу в один запрос. Он и будет искать эти все слова разом, а не по отдельности. Или я не прав?
27 Garykom
 
гуру
13.12.22
11:38
(24) дык хотя бы строки с одинаковым кол-вом слов сгруппируй и одним запросом
28 Oleg37701
 
13.12.22
11:39
(27) Хорошая идея, попробую, спасибо большое.
29 SleepyHead
 
гуру
13.12.22
11:40
(26) Ну фиг знает, у меня ж работало. Хотя и задача была не такая, как у вас, но же нужно было получать однотипные данные из разных источников. Количество источников заранее было неизвестно.
30 hockeyist
 
13.12.22
11:41
(22) В каком цикле? Попробуй написать этот цикл...
Ужас, что творится. Забили людям голову этими запросами в цикле
31 1Снеговик
 
гуру
13.12.22
12:03
(14) Честно говоря, от 25 конструкций в соединениях "ПОДОБНО %Паста% И ПОДОБНО %АА3% И ПОДОБНО %БЛЕНДАМЕТ%" движок СУБД тоже будет в шоке похлеще запросов в цикле.
32 Oleg37701
 
13.12.22
12:10
(31) Ну вот идея посторения одного огромного запроса меня тож смущает. Если строк будет 100, или 150. Там километровый запрос получится.
33 Oleg37701
 
13.12.22
12:11
(31) И не знаю, будет ли это производительней
34 1Снеговик
 
гуру
13.12.22
12:11
(26) попробуй сначала запросом выбрать все элементы, в которых встречается хотя бы одно слово из введенных пользователем.
Из них формируешь временную таблицу в памяти, а потом для каждой строки в цикле ищи комбинации, будет быстрее... наверное)
Вариантов решения масса. Но надо тестировать как будет быстрее.
35 Oleg37701
 
13.12.22
12:12
(34) Спасибо большое.
36 1Снеговик
 
гуру
13.12.22
12:13
(32) я вот думаю тут запрос в цикле будет оптимален с точки зрения сложности кода) Не стоит прям всегда избегать запросов в цикле, главное решить задачу.

Просто прочитай один раз общую таблицу с наименованиями номенклатуры в менеджер временных таблиц, а оттуда в цикле запросом выбирай по условиям.
37 Garykom
 
гуру
13.12.22
12:28
(36) типовой полнотекстовый поиск или своя реализация (метод N-грам например) тут сильно оптимальней
sql он для подобного не предназначен
38 Said_We
 
13.12.22
12:52
(0) Как сочетаются два утверждения из (0)

1. "Есть табличная часть - запрашиваемая номенклатура (строка) и количество(число)"
2. "Искать нужно по нескольким колонкам."

Собственно где взять несколько колонок, если их только 2-е?
О каком запросе в цикле идет речь?
39 Oleg37701
 
13.12.22
12:53
(38) "Пользователи вводят строкой название запрашиваемой номенклатуры. Далее нужно в *специальном* регистре искать в нескольких колонка это наименование подобно тому, как это происходит при условии "содержит"
40 Oleg37701
 
13.12.22
12:54
(38) В нескольких колонках регистра
41 Said_We
 
13.12.22
12:54
Пример регистра нарисуй, а то не понятно о чем речь.
42 Said_We
 
13.12.22
13:05
(40) Я пока не вижу зачем нужен запрос в цикле. Где собственно цикл? И не мне одному не виден цикл - смотреть (30).
43 hockeyist
 
13.12.22
13:09
(39) И где здесь вообще цикл?
44 1Снеговик
 
гуру
13.12.22
13:10
(42) у тебя есть 30 строк со словами, для каждой надо найти соответствие из регистра с проверкой по каждому слову.
45 hockeyist
 
13.12.22
13:12
(42) В итоге выяснится, что ТС нужно было понять, как

ААА31 Паста Блендамет

превращается в

ПОДОБНО %Паста%
И ПОДОБНО %АА3%
И ПОДОБНО %БЛЕНДАМЕТ%

И даже может быть он бы и сам справился, но кто-то ему сказал, что "должен остаться кто-то один": либо цикл, либо запрос. Вот он и боится цикл рядом с запросом писать
46 hockeyist
 
13.12.22
13:14
(44) Это ты уже сам придумал
47 Said_We
 
13.12.22
13:15
(44) И где цикл?
48 Said_We
 
13.12.22
13:22
(44) У вас де таблицы. Одна берется из регистра. А вторая таблица получена из строки за счет разбивки строки по словам с разделителем пробел.
Если условие "И", то для каждой строки регистра получаешь несколько строк за счет соединения.
Добавляешь расчетное поле в запросе, которое рассчитываешь по правилу: Если СтрокаВРегистре содержит СтрокаПоиска тогда 1 иначе 0 назовем это поле А. И второе поле всегда 1, назовем его Б.
Потом суммируешь эти два поля и где условие HAVING Сумма(А) = Сумма(Б)

Если условие ИЛИ, то второе поле И не нужно, а условие будет HAVING Сумма(А) > 0
49 Said_We
 
13.12.22
13:39
(40) Структуру регистра рисуй. Что за регистр (РН, РС, РР...), какие измерения у этого регистра. Какого типа все поля регистра. По каким полям надо искать.
50 Kassern
 
13.12.22
13:44
(48) Простой пример
Есть тест со следующими строками
1)ААА31 Паста Блендамет
2)Батарейка ААА зайчик

Есть регистр со следующими строками
1)Паста Блендамет ААА31
2)ААА31 Паста Блендамет
3)Паста Блендамет ААА31 со кусом клубники
4)Батарейка Панасоник зайчик ААА
5)ААА зайчик филипс батарейка
6)Батарейка зайчик  

Так вот для первой строки нужно вывести 1,2,3 регистра, для второй строки 4,5 соответственно судя по (0).

В Вашем же случае из (48) Вы просто получаете перечень слов без привязки к строкам, поэтому вряд ли это решение подойдет. Или я как-то не понял, что вы имели в виду за вторую таблицу.
51 Said_We
 
13.12.22
13:50
(50) Из строк теста по строкам можно получить таблицу с двумя колонками. Или с тремя - как хотите.

Номер поиска | строкаПоиска
1               ААА31
1               Паста
1               Блендамет
2               Батарейка
2               ААА
2               зайчик

Раз условие И, тогда условие: HAVING Сумма(А) = Сумма(Б)

Собственно результат условие для первой строки поиска даст истину для строк регистра 1,2,3, а для 2-й даст истину для строк 4 и 5.
52 Said_We
 
13.12.22
13:57
(50) Осталось только с типом строки в регистре разобраться. Вдруг там строка неограниченной длины :-)
Реализации текста запроса для строки ограниченной длины и неограниченной длины будут разные.
53 Kassern
 
13.12.22
13:58
(52) Есть же Подстрока
54 Said_We
 
13.12.22
13:59
(53) Группировать по строке неограниченной длины нельзя. А обрезать не нужно.
55 Said_We
 
13.12.22
14:08
В общем запроса в цикле тут я не вижу. Автор куда-то исчез. Пояснений более нет. Может автор уже понял как реализовывать и ваяет. :-)
56 Kassern
 
13.12.22
14:17
(55) Цикл всегда может быть и это даже будет правильно, если исходная таблица будет гигантская, тогда лучше разбить на пакеты и в цикле обработать в запросе)
57 1Снеговик
 
гуру
13.12.22
14:19
(53) вообще-то в запросе есть и СТРНАЙТИ
58 Kassern
 
13.12.22
14:20
(57) С какой версии платформы?
59 Eiffil123
 
13.12.22
14:30
(0) а что плохого в запросе в цикле в рамках данной задачи? врядли пользователь набивает значения быстрее
60 Kassern
 
13.12.22
14:30
(51) Я так и не понял, как у вас Сумма(А) = Сумма(Б)  будет равна в разрезе номеров строк?
Можете примерный текст запроса накидать, что группируете и как соединяете таблицы?
61 Kassern
 
13.12.22
14:32
(51) Вот вам для тестов)
ТЗ=Новый ТаблицаЗначений;
    ТЗ.Колонки.Добавить("НомерСтроки",Новый ОписаниеТипов("Число"));
    ТипСтрока=Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(20));
    ТЗ.Колонки.Добавить("СтрокаПоиска",ТипСтрока);
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=1;
    НовСтрока.СтрокаПоиска="%ААА31%";
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=1;
    НовСтрока.СтрокаПоиска="%Паста%";
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=1;
    НовСтрока.СтрокаПоиска="%Блендамет%";
    
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=2;
    НовСтрока.СтрокаПоиска="%Батарейка%";
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=2;
    НовСтрока.СтрокаПоиска="%ААА%";
    НовСтрока=ТЗ.Добавить();
    НовСтрока.НомерСтроки=2;
    НовСтрока.СтрокаПоиска="%зайчик%";
    //
    Реестр=Новый ТаблицаЗначений;
    Реестр.Колонки.Добавить("Наименование",Новый ОписаниеТипов("Строка",,,,Новый КвалификаторыСтроки(40)));
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="Паста Блендамет ААА31";
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="ААА31 Паста Блендамет";
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="Паста Блендамет ААА31 со кусом клубники";
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="Батарейка Панасоник зайчик ААА";
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="ААА зайчик филипс батарейка";
    НовСтрока=Реестр.Добавить();
    НовСтрока.Наименование="Батарейка зайчик";
62 Said_We
 
13.12.22
15:32
(57) В данной задаче не нужно знать где именно в строке находится подстрока. Важно знать есть она или нет. Так что LIKE тут более чем достаточно.
(60) Если очень примерно и для понимания, то запрос ниже. 1С запрос не поддерживает select (select ...). Вместо этого в 1С придется писать "inner join", как это сделать думаю понятно. Если Строка, в которой ищем является строкой ограниченной длины, то запрос проще. Нумеровать вторую таблицу тогда не нужно, а группировать прямо по S можно. Вторую таблицу тоже пронумеровал, только для информативности, что бы понятно было по какой строке поиска получен результат.

with t1 as
(SELECT 1 as npp, 'ААА31' as s
UNION ALL SELECT 1, 'Паста'
UNION ALL SELECT 1, 'Блендамет'
UNION ALL SELECT 2, 'Батарейка'
UNION ALL SELECT 2, 'ААА'
UNION ALL SELECT 2, 'зайчик'
)

,t2 as
(SELECT
    row_number() over() as npp, t.s as s
from
    (SELECT    'Паста Блендамет ААА31' as s
    UNION ALL SELECT 'ААА31 Паста Блендамет'
    UNION ALL SELECT 'Паста Блендамет ААА31 со кусом клубники'
    UNION ALL SELECT 'Батарейка Панасоник зайчик ААА'
    UNION ALL SELECT 'ААА зайчик филипс батарейка'
    UNION ALL SELECT 'Батарейка зайчик'
    ) as t
)

SELECT
     t.npp2 /*строка по порядку, в итоговом запросе нужна только для информативности*/
     ,(SELECT s from t2 as t2 WHERE t2.npp = t.npp2 LIMIT 1) as s /*так если строка неограниченной длины, иначе можно групировать по S и поле npp2 не нужно*/
     ,t.npp1 /*это номер поиска для информативности, когда понятно убрать*/
FROM
    (SELECT
         t2.npp as npp2
        ,t1.npp as npp1
        ,sum(iif(t2.s like '%'|| t1.s ||'%', 1 , 0)) as A
        ,sum(1) as B
    FROM t2 as t2
    LEFT JOIN t1 as t1 on 1=1

    GROUP by
        t2.npp, t1.npp
    HAVING
        A=B
    ) as t

Это результат (батарейка с большой и маленькой буквы, поэтому 5 не попало, но можно отвязаться от заглавных и строчных букв):
npp2    s                                            npp1
1    Паста Блендамет ААА31                             1
2    ААА31 Паста Блендамет                             1
3    Паста Блендамет ААА31 со кусом клубники             1
4    Батарейка Панасоник зайчик ААА                     2
63 Said_We
 
13.12.22
16:39
(60) В (62) запрос рабочий. По быстрому в SQLite набросал.
"||" это конкатенация строк. Заменить на "+".
"LIMIT 1" равноценно  "TOP 1", но в 1С не понадобиться так как необходимо будет рисовать внизу "INNER JOIN t2 as t2 ON t2.npp = t.npp2" и в select напрямую брать t2.s.
with аналог в 1С "ПОМЕСТИТЬ"
"row_number() over() as npp" добавить колонку нумерации всех строк от первой до последней как есть без сортировки.
"iif(" это короткая запись "ВЫБОР КОГДА... ТОГДА ... ИНАЧЕ.. КОНЕЦ", если по аналогии с обычным языком 1С то "?(условие, ЗначениеЕслиУсловие_ИСТИНА, ЗначениеЕслиУсловие_ЛОЖЬ)".

Собственно наверное всё пояснил.... На языке запросов 1С это без проблем пишется.
64 Said_We
 
13.12.22
17:36
Если бы автор в ответ на (41) дал бы структуру регистра где ищем, то написал бы запрос на 1С. А так нарисовал общий случай.
Автору, по всей видимости, уже не нужно.
65 Oleg37701
 
13.12.22
17:39
(64) Отходил.

В чем суть.

В регистре сведений содержатся записи предложений от поставщиков. Колонки условно - стоимость, количество, наименование поставщика, артикул, наше наименование

В табличной части документа, мы указываем наименование, которое нужно найти. Ищем по 3 колонкам - наименование поставщика, артикул, наше наименование.
66 Oleg37701
 
13.12.22
17:40
(64) Поиск должен быть по логике "сожержит" не пуля в пулю. Пример указал выше. Таких строк может быть 25, 50, 90
67 Oleg37701
 
13.12.22
17:44
(65) Если в одной из колонок нашли, выводим.
68 Said_We
 
13.12.22
18:02
(65) "В регистре сведений содержатся" - уже хорошо. С типом регистра разобрались. Какие измерения у регистра и размерность всех полей, включая измерения?
(67) Если в одной из, это условие не И, а ИЛИ. Так? Если так то правильнее в списке на выбор показывать сначала более подходящие, а потом менее. Так? Если так, то отсортировать по количеству найденных подстрок.
69 Oleg37701
 
13.12.22
18:07
(68)  стоимость, количество, наименование поставщика, артикул, наше наименование - все ресурсы. Все, кроме наше наименование стороковые. Наше наименование - ссылка на номенклатуру.

Если в одной из, это условие не И, а ИЛИ - Да

Если так то правильнее в списке на выбор показывать сначала более подходящие, а потом менее - без разницы.

В каком приоритете показывать - не важно. Главное пройти по всем строкам ТЧ и найти те, что содержат запрашиваемую номенклатуру.
70 Said_We
 
13.12.22
18:11
(69) Если условие ИЛИ, то "HAVING A>0". Уже писал. Одно условие меняется.
71 Oleg37701
 
13.12.22
18:13
(70) Я не знаю чисты язык скуля. Вы предлагаете разделить всю запрашиваемую номенклатуру на отдельные слова. И выгрузить в таблицу. И эту таблицу передавать в запрос?
72 Said_We
 
13.12.22
18:18
(71) На языке запрос 1С тоже самое будет примерно.
"Все, кроме наше наименование стороковые" - размерность строки какая?

На сколько я понял задачу, то пользователь вводит одну или несколько отдельных строк и по этим строкам ищется с таблице наша строка, которая будут содержать все слова для каждой отдельной строки поиска. Поэтому в примере и нарисовал две строки, по которым ищется.

"Вы предлагаете разделить всю запрашиваемую номенклатуру на отдельные слова" - нет у вас на входе несколько строк. Их и делите на слова и помещайте в ТЗ и её в запрос.
73 Oleg37701
 
13.12.22
18:20
(72) "Размерность строки какая" - 300
74 Said_We
 
13.12.22
18:20
(73) Главное что не безразмерная.
75 Oleg37701
 
13.12.22
18:21
(74) Строку в ресурсах и измерениях, насколько знаю нельзя сделать неограниченной длинны.
76 Oleg37701
 
13.12.22
18:22
(75) Но могу ошибаться
77 Said_We
 
13.12.22
18:28
(76) Пробуйте. Вся необходимая информация есть.
78 Volodja
 
15.12.22
08:51
(62) Запомню себе. Попробую
Оптимист верит, что мы живем в лучшем из миров. Пессимист боится, что так оно и есть.