Конвертировать VARCHAR в INT / NUMBER в предложении WHERE - PullRequest
0 голосов
/ 02 мая 2018

У меня есть таблица ACTIVITIES_T в БД PostgreSQL. ACTIVITY_CODE - это столбец VARCHAR:

ID (INT)  |  ACTIVITY_CODE (VARCHAR) | ACTIVITY_TEXT (VARCHAR)
-------------------------------------------------------------
..            ..                      ..
7             10012                   ..
8             10013                   ..
9             10014                   ..
10            10015                   ..
11            SPECIAL                 ..

У меня есть непрерывный блок псевдо-чисел, 10012..10015, который мне нужно выбрать с помощью оператора BETWEEN a AND b, или >= n1 and <= n2.

Но не все записи в ACTIVITY_CODE являются числовыми значениями.
Я попробовал это:

select * from activities_t  where activity_code::int >= 10012 and 
                                  activity_code::int <= 10015;

но получил ошибку

ERROR:  invalid input syntax for integer: SPECIAL

Ответы [ 2 ]

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

Просто добавьте к тому, что написал @ Эрвин Брандстеттер , если использовать это в Spring Data, будут жалобы на использование оператора :: из вашего @ Query.

Чтобы исправить это, экранируйте ::, как показано в этом примере, https://stackoverflow.com/a/43982706/1005607

\\:\\:

Или, в качестве альтернативы, измените запрос для использования функции cast.

@Query(value="select * from activities_t where " + 
             "   case when  activity_code ~ '^\d+$' " +  // only digits   
             "   then cast(activity_code as int) between 10012 and 10015 end ", 
       nativeQuery=true)
public List<ActivityT> getByActivityCodes();
0 голосов
/ 02 мая 2018
SELECT *
FROM   activities_t
WHERE  CASE WHEN activity_code ~ '^\d+$'  -- only digits
            THEN activity_code::int BETWEEN 10012 AND 10015 END;

Оболочка CASE исключает исключение. Рассматриваются только строки, состоящие только из цифр. (Так что без пробелов тоже!)
ELSE не требуется, поскольку CASE по умолчанию равно NULL и только TRUE соответствует условию WHERE.

Конечно, это не может использовать какой-либо простой индекс для activity_code.

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

CREATE INDEX foo_idx ON activities_t((CASE WHEN activity_code ~ '^\d+$'
                                           THEN activity_code::int END));

И сопоставьте выражение в вашем запросе:

SELECT *, CASE WHEN activity_code ~ '^\d+$' THEN activity_code::int END
FROM   activities_t
WHERE  CASE WHEN activity_code ~ '^\d+$'
            THEN activity_code::int END BETWEEN 10012 AND 10015;

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

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