Проблемы с хранением числовых данных в текстовых столбцах - ВЫБРАТЬ ... МЕЖДУ - PullRequest
0 голосов
/ 10 декабря 2008

Несколько лет назад я работал в системе, в которой числовой первичный ключ хранился в столбце [SQL Server] varchar, поэтому я быстро оторвался при запросе с оператором BETWEEN:

SELECT ID FROM MyTable WHERE ID BETWEEN 100 AND 110;

Результаты:

100
102
103
109
110
11

Это был просто плохой дизайн. Тем не менее, я работаю над сторонней ERP-системой, которая, как вы можете себе представить, должна быть универсальной и гибкой; таким образом, у нас есть различные таблицы, в которых предусмотрены буквенно-цифровые поля, в которых бизнес использует только цифры - поэтому могут возникнуть похожие проблемы.

Я предполагаю, что это достаточно распространенная проблема; У меня есть достаточно простое решение, но мне любопытно, как другие решают такие проблемы.

Мое простое решение:

SELECT ID FROM MyTable 
WHERE ID BETWEEN iStartValue AND iEndValue 
AND (LENGTH(ID) = LENGTH(iStartValue)
 OR LENGTH(ID) = LENGTH(iEndValue));

Как вы, возможно, можете сказать, это система Oracle, но я обычно работаю в SQL Server - так что, возможно, предпочтительны решения, независимые от базы данных.

Редактировать 1: Поцарапайте это - я не понимаю, почему проприетарные решения также не приветствуются.

Редактировать 2: Спасибо за все ответы. Я не уверен, разочарован ли я, что нет очевидного, изощренного решения, но, соответственно, я рад, что, похоже, я ничего не упустил!

Я думаю, что я все еще предпочитаю свое собственное решение; это просто и работает - есть ли причина, почему я не должен использовать это? Я не могу поверить, что это намного, если таковые имеются, менее эффективно, чем другие решения.

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

Ответы [ 5 ]

7 голосов
/ 10 декабря 2008

Если вы уверены, что значения в ID являются только числовыми, то почему бы просто не ЗАБРАТЬ их

WHERE CAST(ID as int) BETWEEN iStartValue AND iEndValue

РЕДАКТИРОВАТЬ 1: Расширение метода приведения, который должен работать, заключается в использовании подзапроса для извлечения всех числовых записей. Пожалуйста, обратите внимание - я не думаю, что этот метод лучше, чем предложенный выше, я включаю его, поскольку он решает проблему !!!

SELECT ID 
FROM    (
    SELECT  ID
    FROM    MyTable 
    WHERE   ISNUMERIC(ID) = 1
    AND CHARINDEX ('.', ID) = 0
    AND CHARINDEX ('-', ID) = 0
    ) a
WHERE   CONVERT(bigint, ID)  BETWEEN 0 AND 12000
ORDER BY LENGTH(ID) ASC, ID

Проверка «-» и «.» персонажи на самом деле не требуются. Я предполагаю, что ваши идентификаторы не могут быть отрицательными или десятичными.

2 голосов
/ 10 декабря 2008

Не знаю, может ли это сработать в вашей ситуации, но ...

Как насчет добавления фактического числового столбца в таблицу, заполненную значением (в SQL Server можно использовать вычисляемый столбец с установленным постоянным индексом)

В БД других поставщиков используется какой-то другой механизм для заполнения (триггер, материализованное представление и т. Д.)

и затем используйте этот столбец вместо одного столбца ...

1 голос
/ 10 декабря 2008

Другим вариантом будет добавление слева чисел к нулю и использование в них оператора между. По соображениям саргидности, вероятно, лучше включить это как второе условие условия (чтобы все еще можно было использовать возможные индексы). Как то так ...

SELECT ID FROM MyTable 
WHERE  ID BETWEEN iStartValue AND iEndValue 
       And Right('0000000000' + ID, 10) Between iStartValue and iEndValue 

Я проверил это в SQL Server, и он возвращает правильные значения. Возможно, вам придется изменить это для работы с Oracle.

1 голос
/ 10 декабря 2008

Возможно, LPAD (id, 12, '') будет работать для вас. Все значения столбцов должны иметь ширину 12 с пробелами слева.

Кроме того, меня немного беспокоят цифры в столбцах varchar2.

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

1 голос
/ 10 декабря 2008

А как насчет броска?

SELECT ID FROM MyTable 
WHERE cast(ID as signed) BETWEEN cast(iStartValue as signed) AND cast(iEndValue as signed)

Данный синтаксис задан как MySQL, но для T-SQl существуют аналогичные операторы CAST.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...