powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Применить ряд правил из таблицы к одной строке в чистом SQL
25 сообщений из 40, страница 1 из 2
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323750
Есть поле VARCHAR(2000)
Вносятся туда данные вида

ДокументОплатаБанк
СотрудникВыплата
ДокументНалогБанкСотрудник

Задача: взять словарь (табличка) и по нему сократить эти названия.

Длинное Название Короткое названиеДокумент ДокСотрудник СотрБанк Б

Могу решить на PL\SQL (запускаю цикл по табличке и делаю REPLACE на каждую запись справочника), но как решить на чистом SQL - не знаю.
CONNECT BY мог бы помочь, но я не совсем понимаю как его можно подключить.

Подскажите пожалуйста, как можно соединить таблицу с данными и справочник так, чтобы весь справочник сокращений можно было применить.
Заранее спасибо.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323791
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Магика де Гипнос,

MODEL или рекурсия.

SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323793
j2k
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Магика де Гипнос,

можно поискать по форуму
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323806
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну каков вопрос - таков ответ :)
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
with t(id, str) as (select 1, 'ДокументОплатаБанк'
from dual union all select 2, 'СотрудникВыплата'
from dual union all select 3, 'ДокументНалогБанкСотрудник'
from dual)
, dic (lname,sname) as (select 'Документ', 'Док'
from dual union all select 'Сотрудник', 'Сотр'
from dual union all select 'Банк', 'Б'
from dual)
--------------------------------------
, r (id, str, rep) as (
select id, str, replace(str,lname,sname) from t, lateral(select lname,sname from dic where str like '%'||lname||'%' order by lname fetch first '1' rows only)
union all
select id, str, replace(rep,lname,sname) from r, lateral(select lname,sname from dic where rep like '%'||lname||'%' order by lname fetch first '1' rows only)
)
search depth first by rep set o
cycle rep set cycle to 'Y' default 'N'
select id, str, max(rep) keep (dense_rank last order by o) rep
from r group by id, str
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323841
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymous,

А не проще ли:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
with t(id, str) as (
                    select 1, 'ДокументОплатаБанк' from dual union all
                    select 2, 'СотрудникВыплата' from dual union all
                    select 3, 'ДокументНалогБанкСотрудник' from dual
                   ),
dic (lname,sname) as (
                      select 'Документ', 'Док' from dual union all
                      select 'Сотрудник', 'Сотр' from dual union all
                      select 'Банк', 'Б' from dual
                     ),
s(cnt,rn,lname,sname) as (
                          select  count(*) over(),row_number() over(order by 1),lname,sname from dic
                         ),
r (cnt,rn,id,str,rep) as (
                           select cnt,rn,id,str,replace(str,lname,sname) from t,s where rn = 1
                          union all
                           select cnt,s.rn,id, str, replace(rep,lname,sname) from r,s where s.rn = r.rn + 1
                         )
select id, str, rep
from r where rn = cnt
/




SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323862
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYА не проще ли:
Ну не знаю.
И исходный вариант на сахар, а это решение - вообще злой cartesian join по факту.
Я даже в порядке шутки юмора такое писать морально не готов :)
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39323895
andreymx
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
такой себе переводчик русско-украинский
тупой, чисто замена слово-слово, даже без учета смены рода при переводе, но кого-то устраивает и таки как-то работает
+ пропускает слова из цифр и англобукв
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
        WITH
        --q AS (SELECT 'Машина упаковочная пневматическая ПМУ-002' NAME FROM dual),
        --q AS (SELECT 'Комплекс отладочный ПРТХ 656141.074' NAME FROM dual),
        --q AS (SELECT 'Коммутатор Zyxel IES-1000 EE в комплекте' NAME FROM dual),
        q AS (SELECT TRANSLATE_PKG.get_true_word(p_name) NAME FROM dual),
        --q AS (SELECT 'Диван кожаный' NAME FROM dual),



        T AS (SELECT NAME, LENGTH(NAME) l FROM q)
        --SELECT * FROM t;
        ,
        t1 AS
        (
        SELECT SUBSTR(NAME, LEVEL, 1) b, LEVEL l, NAME
          FROM T
        connect BY LEVEL <= l
        )
        --SELECT * FROM t1;
        ,
        words AS
        (
        SELECT listagg(b) WITHIN GROUP(ORDER BY l) rus,
               DENSE_RANK() OVER(ORDER BY MIN(l)) dr, MIN(l) min_l
        FROM
            (
            SELECT 
                   CASE
                        WHEN is_russian_lead = 1 AND is_russian_lag=1 THEN
                            CASE WHEN LOWER(B) IN 'p' THEN 'р'
                                 WHEN LOWER(B) IN 'o' THEN 'о'
                                 WHEN LOWER(B) IN 'a' THEN 'а'
                                 ELSE b
                            END
                        ELSE b
                   END b,
                   l, is_letter, SUM(is_letter) OVER(ORDER BY L) grp
              FROM(
                SELECT b, l,
                       CASE
                            WHEN b BETWEEN '0' AND '9' THEN 0
                            WHEN LOWER(b) BETWEEN 'a' AND 'z' THEN 0
                            WHEN LOWER(b) BETWEEN 'а' AND 'я' THEN 0
                            ELSE 1
                       END IS_LETTER,
                       lead(CASE WHEN LOWER(b) BETWEEN 'а' AND 'я' THEN 1 END) OVER(ORDER BY l) is_russian_lead,
                       lag (CASE WHEN LOWER(b) BETWEEN 'а' AND 'я' THEN 1 END) OVER(ORDER BY l) is_russian_lag,
                       CASE WHEN LOWER(b) BETWEEN 'а' AND 'я' THEN 1 END is_russian
                  FROM t1
                  )
            )
        GROUP BY is_letter, grp
        ),
        DATA AS
        (
        SELECT DUMP(w.rus), w.*,
               CASE
                    WHEN w.rus = INITCAP(w.rus) THEN INITCAP(d.UKR)
                    WHEN w.rus = UPPER  (w.rus) THEN UPPER  (d.UKR)
                    ELSE LOWER(d.UKR)
               END UKR,
               MAX(dr) OVER() dr_max,
               CASE WHEN d.UKR IS NULL THEN
                    CASE
                        WHEN LENGTH(' '||TRANSLATE(LOWER(w.rus), 'ф-xх1234567890*()[],.+/=#№?&@', 'ф'))<=3 THEN w.rus
                    END
               END skipped,
               skp.rus skipped_spr,
               -- если есть несколько вариантов расшифровки, возьмём тот, который совпалдает по номеру группы)
               DENSE_RANK() OVER(PARTITION BY dr ORDER BY d.group_mater) dr_group 
          FROM words w,
               (SELECT * FROM DICTIONARY_RUS_UKR d WHERE D.GROUP_MATER IS NULL OR D.GROUP_MATER = p_group_mater) d,
               DICTIONARY_RUS_UKR_SKIPPED skp
         WHERE d.rus_lower  (+) = LOWER(w.rus)
           AND skp.rus_lower(+) = LOWER(w.rus)
         ORDER BY
               w.dr
        )
        --SELECT *   FROM DATA;

        SELECT DISTINCT
               rus, UKR, LEVEL,
               -- из-за того, что разделителем в SYS_CONNECT_BY_PATH не может быть спецсимвол, а разделитель нужен обязательно,
               -- мы букву 'а' меняем на CHR(1) и эту букву 'а' уже используем в SYS_CONNECT_BY_PATH в качестве разделителя,
               -- потом ее удаляем как ненужную, а затем меняем CHR(1) назад на 'а'
               REPLACE(REPLACE(SYS_CONNECT_BY_PATH(REPLACE(NVL(UKR, rus)        , 'а', CHR(1)), 'а'), 'а', ''), CHR(1), 'а') UKR_result,
               REPLACE(REPLACE(SYS_CONNECT_BY_PATH(REPLACE(CASE WHEN UKR||skipped||skipped_spr IS NULL THEN rus||' ' END
                                                                                , 'а', CHR(1)), 'а'), 'а', ''), CHR(1), 'а') not_found,
               REPLACE(REPLACE(SYS_CONNECT_BY_PATH(REPLACE(skipped    ||' '     , 'а', CHR(1)), 'а'), 'а', ''), CHR(1), 'а') skipped,
               REPLACE(REPLACE(SYS_CONNECT_BY_PATH(REPLACE(skipped_spr||' '     , 'а', CHR(1)), 'а'), 'а', ''), CHR(1), 'а') skipped_spr
          FROM (SELECT * FROM DATA WHERE dr_group=1)
        WHERE dr = dr_max
        start WITH dr=1
        connect BY PRIOR dr = dr-1

...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324084
Спасибо большое всем откликнувшимся.
В данный момент реализовали при помощи функции, где в PL\SQL по циклу происходит перебор словаря.
Используется как временное решение, поэтому сегодня-завтра выберу самый красивый способ из предложенных и применю.
Спасибо большое.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324119
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousНу не знаю.
И исходный вариант на сахар, а это решение - вообще злой cartesian join по факту.
Я даже в порядке шутки юмора такое писать морально не готов :)

Cartesian join сделает REPLACE всех строк. LIKE проверит все строки + REPLACE где LIKE. С другой стороны LIKE чуть быстрее и ищет до первого соотвествия. Так-что в данном случае баш на баш и я морально готов :) к cartesian join.

SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324136
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Магика де ГипносСпасибо большое всем откликнувшимся.
В данный момент реализовали при помощи функции, где в PL\SQL по циклу происходит перебор словаря.
Используется как временное решение, поэтому сегодня-завтра выберу самый красивый способ из предложенных и применю.
Спасибо большое. Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324142
982183
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Задача учебная или практическая?
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324143
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.

Это почему? Что в данной задаче PL/SQLьного? Что кроме nested loop PL/SQL тут может предложить?

SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324144
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYCartesian join сделает REPLACE всех строк. LIKE проверит все строки + REPLACE где LIKE.
Вариант с like дает rowsource меньшего размера - на существенных объемах предпочтительнее.
Представьте табличку T миллионов на 100-200 записей и словарик на ~500 статей - по cartesian получаем rowsource в 50-100 ярдов записей.
Вариант с фильтром оценочно выдаст "нагора" 300-500 миллионов.
С другой стороны, в Вашем варианте не требуется группировка...
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324145
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopМагика де ГипносСпасибо большое всем откликнувшимся.
В данный момент реализовали при помощи функции, где в PL\SQL по циклу происходит перебор словаря.
Используется как временное решение, поэтому сегодня-завтра выберу самый красивый способ из предложенных и применю.
Спасибо большое. Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.
Вот научится оракель pl/sql в parallel гонять без извратов - тогда обсудим масштабируемость.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324149
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousПредставьте табличку T миллионов на 100-200 записей и словарик на ~500 статей - по cartesian получаем rowsource в 50-100 ярдов записей.
Вариант с фильтром оценочно выдаст "нагора" 300-500 миллионов.
С другой стороны, в Вашем варианте не требуется группировка...


Ну это вопрос temp space. И для сортировки (причем двойной) 300-500 миллионов его тоже понадобится прилично.

SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324153
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousdbms_photoshopпропущено...
Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.
Вот научится оракель pl/sql в parallel гонять без извратов - тогда обсудим масштабируемость.Имеется в виду отсылка к особенностям pipelined? 19746366
Во-первых на них свет клином не сошелся и еще есть dbms_parallel_execute с материализацией результата в отдельном сегменте.

Во-вторых плохая масштабируемость означает, что скорость роста времени выполнения от объема данных разная.
Иными словами, после определенного предела serial PL/SQL execution гарантированно уделает SQL подходы (recursive subquery factoring или model).
Есть весьма экзотические задачи на которых эти два инструмента смотрятся достойно, но пока о них говорить не буду. :)
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324170
Фотография Elic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshop Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.Плюс PL/SQL сопровождаемей.
А на 12с его можно писать и прямо в запросе.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324175
SYЧто кроме nested loop PL/SQL тут может предложить?Что, кроме nested loop, может предложить sql?
Кроме того, рассматривается простейший алгоритм без учета конфликтов кодирования. Хотя, может быть, заглавные буквы делят исходную строку на слова, тогда есть варианты сначала парсить строку.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324288
982183Задача учебная или практическая?
Стыдно признаться, но практическая.
Раньше в подобных случаях мы собирали функцию, которая на вход брала строку, прогоняла через словарь и выдавала измененный вариант.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324491
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopеще есть dbms_parallel_execute с материализацией результата в отдельном сегменте.
Это и есть изврат, не всякой задаче подходит.
К примеру, как там у dbms_parallel_excute дела с read consistency?
А как обрабатывать исключения в одном из потоков, если надо обеспечить атомарность _всей операции?
Ну и совсем уже мелочь - каждый из параллельных процессов dbms_parallel_excute самостоятельно просканирует источник, что в условиях отсутствия индексов кратно увеличит io.
Можно, наверное, попробовать дать им всем один ref cursor в качестве параметра, пусть дерутся... если нет межстрочных зависимостей.

parallel pipelined, по крайней мере, нормально работают в одной транзакции и разделяют общий dataset.

Про "гарантированно медленнее" на больших объемах - не согласен.
Зависит, знаете ли.

Пусть PL/SQL гонит могучий параллельный курсор (ведь даже просто отсортировать входной набор для PL/SQL - штука затратная, в параллель существенно легче/быстрее), но ведь весь датасет в итоге соберется на одно процессорное ядро. Если нет вычислений - да и Бог с ним, но если есть - то лучше выполнить на слейвах.
Хотите сделать на PL/SQL межстрочные вычисления?
Тогда понадобится память.
Иногда - Много памяти.
С сожалению, один процесс не может без грубого хака скушать более 5% PGA_TARGET.
А много параллельных - могут :)

Дальше после вычислений итоговый датасет надо куда-то протолкнуть - в тот же merge, например.
Тут тоже бывает выгодно использовать parallel_dml.
А если так - то зачем собирать датасет в одну кучу, если затем опять раскидывать?

К чему это все?
Я согласен с тезисом Elic, что PL/SQL в ряде случаев легче сопровождать.
Но не согласен с dbms_photoshop, что в текущей реализации PL/SQL большие объемы - его призвание.
pipelined в качестве компромисса - вариант приемлемый, и у него, на мой взгляд, больше шансов подружиться с большими объемами.
Ну и аналитика тоже, на самом деле, работает неплохо - до тех пор, пока не начинаем ей жонглировать, выстраивая в несколько этажей с разными окнами, сортировками и partitioning.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324493
Фотография andrey_anonymous
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Магика де Гипнос982183Задача учебная или практическая?
Стыдно признаться, но практическая.
Тогда очень внимательно отнеситесь к порядку, в котором применяются правила замены из словаря.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324519
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andrey_anonymousПро "гарантированно медленнее" на больших объемах - не согласен.
Зависит, знаете ли.Конкретный пример в студию.
Предлагаю создать отдельный топик вида: вот задача и вот ее решение на recursive subquery factoring/model которое быстрее решения PL/SQL.
(за исключением построения иерархий или списков при наличии нормальных индексов и recursive subquery factoring, хотя и тут после определенного предела начинаются чудеса с чтением блоков в current mode и прочими деградациями)

Все остальное - пустое сотрясание воздуха.

Большие объемы - призвание хадупа, Оракл со своим максимумом 2ГБ на процесс (невероятно что это идиотское ограничение не сняли даже в 12с) и нелинейной масштабируемостью неврно курит в сторонке. Но это тема другой дискуссии.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324529
Вячеслав Любомудров
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dbms_photoshopОракл со своим максимумом 2ГБ на процесс (невероятно что это идиотское ограничение не сняли даже в 12с)Что за ограничение?
Для workarea насколько помню 4Г (по крайней мере перестройка индекса съедает столько), для сессионных переменных -- до 16Г (просто я больше не видел)
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324545
Фотография SY
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Магика де ГипносСтыдно признаться, но практическая.
Раньше в подобных случаях мы собирали функцию, которая на вход брала строку, прогоняла через словарь и выдавала измененный вариант.

Вообще-то задача совсем не про масштабируемость (вернее не про масштабируемость размера тaблицы а про масштабируемость скорости вставки), cartesian join и прочее. Ведь короткое название опрeделяется при insert/update. Так-что тут скорее всего как быстрее в триггере/коде insert/update. Если так, то я бы:

1. Создал пакет в котором есть только блок инициализации.
2. Блок инициализации засасывает словарь (надеюсь словарь не БСЭ ) в ассоциативный массив с index by varchar2 со значениями массив(длинное_название) := короткое_название;
3. При insert/update (при update тoлько если :new.длинное_название != :old.длинное_название) бегаем в цикле по словам длинное_название, используем массив для сокращения слов и собирaем в короткое_название.

SY.
...
Рейтинг: 0 / 0
Применить ряд правил из таблицы к одной строке в чистом SQL
    #39324554
Фотография dbms_photoshop
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SYdbms_photoshop Все SQL способы для данной задачи будут медленнее и со значительно худшей масштабируемостью чем PL/SQL.

Это почему? Что в данной задаче PL/SQLьного? Что кроме nested loop PL/SQL тут может предложить?

SY.Еще раз, товарищи: в этой задаче особенного то, что на SQL она решается через rec with/model.
Оба этих инструмента после определенной границы вообще не конкуренты PL/SQL.
Одно дело баловаться на форуме в пятничных задачках и демонстрировать познания в новых фичах, другое дело иметь код в продакшене.
Для наборов данных порядка 10к строк может смотреться более менее терпимо.
Для миллиона строк практически нереально придумать что-то решаемое rec with/model и быстрее PL/SQL.

Некоторые балуются слейкой и разделением строк моделью, некоторые итеративно применяют правила с помощью rec with.
Это все просто баловство и разминка для ума либо для небольших наборов данных.

Вон было "прекрасное" решение моделью. 11567017 Что там с масштабируемостью?

Есть конкретные варинты опровергнуть - только приветстуются. Не поленюсь написать скриптик, чтоб показать дерградацию наглядно еще раз.
...
Рейтинг: 0 / 0
25 сообщений из 40, страница 1 из 2
Форумы / Oracle [игнор отключен] [закрыт для гостей] / Применить ряд правил из таблицы к одной строке в чистом SQL
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]