использовать строковое значение как числовое значение в Oracle - PullRequest
0 голосов
/ 07 мая 2018

У меня есть условие в моем запросе оракула:

AND a.ACCARDACNT > '0880080200000006' and a.ACCARDACNT < '0880080200001000'

тип столбца ACCARDACNT в таблице varchar и проиндексирован, но в этом состоянии я хочу использовать его в качестве числа. Когда я выполняю этот запрос, план выполнения показывает, что CBO может использовать индекс и сканировать таблицу по индексу. это правда?

Я хочу использовать и сравнивать их как числа, а также использовать в качестве индекса. Есть ли решение?

Ответы [ 6 ]

0 голосов
/ 07 мая 2018

Вы должны создать индекс функции для столбца: accardacnt и

create index idx_fn_accardant on table_name( to_number(accardacnt) );

преобразовать его в число в предложении where запроса:

where to_number(ACCARDACNT) > 0880080200000006 and to_number(ACCARDACNT) < 0880080200001000
0 голосов
/ 07 мая 2018

Я думаю, что следующая логика делает то, что вы действительно хотите:

a.ACCARDACNT > '0880080200000006' and
a.ACCARDACNT < '0880080200001000' and
length(ACCARDACNT) = 16

Кроме того, для столбца можно использовать индекс, если он доступен.

Это будет неправильно, если вы хотите, чтобы 15-значный номер учетной записи '880080200000060' соответствовал вашим критериям. Я думаю, что вы не хотите этого.

0 голосов
/ 07 мая 2018

Еще одним вариантом будет вычисляемый столбец:

alter table mytable add accardacnt_num as (to_number(accardacnt));

и укажите один или несколько индексов, содержащих этот столбец:

create index idx_accardacnt_num on mytable(accardacnt_num);

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

and a.accardacnt_num > 880080200000006 and a.accardacnt_num < 880080200001000;
0 голосов
/ 07 мая 2018

Если гарантируется, что все ACCARDACNT являются числами, просто используйте

and to_number(a.accardacnt) > 880080200000006 and a.accardacnt < 880080200001000;

Это гарантирует, что числа не будут сравниваться как строки, где '2' > '10', потому что просмотр первых символов «2» больше, чем «1».

(В случае десятичных чисел убедитесь, что десятичный разделитель, хранящийся в строках, соответствует текущим настройкам сеанса.)

Если вы хотите предоставить индекс для этого, используйте эту функцию index:

create index idx_accardacnt on mytable( to_number(accardacnt) );

или составной индекс, содержащий to_number(accardacnt). Поскольку план выполнения для запроса строк показывает индекс, который будет использоваться, то же самое должно быть верно для числового сравнения и индекса функции. (Помните, что СУБД может свободно использовать предоставленные индексы или нет. Мы просто предлагаем их, но СУБД лучше всего знает, имеет ли смысл использовать их в запросе.)

0 голосов
/ 07 мая 2018

Думаю, вы не можете использовать числовое сравнение и индексировать вместе.

план выполнения показывает, что CBO может использовать индекс

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

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

0 голосов
/ 07 мая 2018

Ваш текущий запрос должен иметь возможность использовать индекс. Но проблема в том, что вы занимаетесь сопоставлением текста, но ожидаете его числовой сортировки. Как правило, это не так, потому что текст сортируется лексикографически в SQL (то есть в порядке словаря). Таким образом, чтобы получить правильное поведение сортировки, вам нужно привести ACCARDACNT к числу:

AND CAST(LTRIM(a.ACCARDACNT, '0') AS FLOAT) BETWEEN 880080200000007 AND 880080200000999
...