Как найти кодовое имя по заданным номерам, используя в SQL (Oracle) - PullRequest
0 голосов
/ 07 сентября 2018

У меня миллионы номеров с разными цифрами от 3 до 8 (121, 1123, 12345678 и т. Д.) Который является ничем иным, как

1 st code    + 2nd Code  +   3rd Code    = Number
     "1"     +     "2"   +      "1"      = 121
    "123"    +     "45"  +      "678"    = 1234567
    "1234"   +      ""   +      ""       = 1234

2-й и 3-й код может быть пустым

у меня есть другая таблица с первым кодом в качестве первичного ключа и кодовым именем

В SQL (Oracle) мне нужно узнать кодовое имя по каждому номеру. Мне наплевать на 2-й код и 3-й код, если найдется самое длинное совпадение с учетом целого числа в качестве 1-го кода

Каков наилучший подход к производительности?

Ответы [ 2 ]

0 голосов
/ 08 сентября 2018

Если вы предпочитаете самый длинный матч, я бы попробовал что-то вроде этого:

select n.num,
       max(c.firstcode) keep (dense_rank last order by length(c.firstcode)) as firstcode,
       max(c.codename) keep (dense_rank last order by length(c.firstcode)) as codename
  from numbers n
  left join codes c on n.num like c.firstcode || '%'
 group by n.num
 order by 1, 2;

Я использовал в основном ту же структуру таблицы и данные, что и @ Питер в его ответе на скрипке.
Для краткости я также использовал неявное приведение типов символов, хотя вместо этого я бы предложил явное приведение (для ясности), например length(to_char(c.firstcode)) вместо length(c.firstcode) и to_char(n.num) like to_char(c.firstcode) || '%' вместо n.num like c.firstcode || '%'.

Пример используемых данных:
Таблица "цифры":

+---------+
|     NUM |
+---------+
|     121 |
|     765 |
|    1234 |
|    3124 |
| 1234567 |
| 3124567 |
+---------+

Таблица «Коды»:

+-----------+----------+
| FIRSTCODE | CODENAME |
+-----------+----------+
|         1 | A        |
|       123 | B        |
|       312 | C        |
|      3124 | D        |
+-----------+----------+

Результат запроса:

+---------+-----------+----------+
|     NUM | FIRSTCODE | CODENAME |
+---------+-----------+----------+
|     121 |         1 | A        |
|     765 |           |          |
|    1234 |       123 | B        |
|    3124 |      3124 | D        |
| 1234567 |       123 | B        |
| 3124567 |      3124 | D        |
+---------+-----------+----------+

Вот SQL Fiddle: http://www.sqlfiddle.com/#!4/958fed/1

Редактировать : Для этого запроса было бы полезно, чтобы столбцы "num" и "firstcode" представляли собой символьные столбцы (и индексированные) вместо числовых.

0 голосов
/ 07 сентября 2018

попробуй, может быть, это простое решение достаточно быстро для тебя?

-- assuming primary key in lookup table is a number
select subq.num,subq.matching_firstcode, 
       (select codename from codes ci where ci.firstcode = subq.matching_firstcode) codename
from (
    select n.num, 
    greatest(
        nvl(c8.firstcode,0),
        nvl(c7.firstcode,0),
        nvl(c6.firstcode,0),
        nvl(c5.firstcode,0),
        nvl(c4.firstcode,0),
        nvl(c3.firstcode,0),
        nvl(c2.firstcode,0),
        nvl(c1.firstcode,0)
    ) matching_firstcode
    from numbers n
    left outer join codes c1 on c1.firstcode = to_number(substr(to_char(n.num), 1, 1))
    left outer join codes c2 on c2.firstcode = to_number(substr(to_char(n.num), 1, 2))
    left outer join codes c3 on c3.firstcode = to_number(substr(to_char(n.num), 1, 3))
    left outer join codes c4 on c4.firstcode = to_number(substr(to_char(n.num), 1, 4))
    left outer join codes c5 on c5.firstcode = to_number(substr(to_char(n.num), 1, 5))
    left outer join codes c6 on c6.firstcode = to_number(substr(to_char(n.num), 1, 6))
    left outer join codes c7 on c7.firstcode = to_number(substr(to_char(n.num), 1, 7))
    left outer join codes c8 on c8.firstcode = to_number(substr(to_char(n.num), 1, 8))
) subq
;

http://www.sqlfiddle.com/#!4/443624/1/0

...