grefon
@grefon

Как на MySQL корректно сортировать строку с числами?

Доброго времени суток. В разработке одного магазина столкнулся с проблемой неправильной сортировки товаров по имени, если у них в названии присутствует число.

Что имеется: база данных MySQL и таблица products с полем name.

В названии товаров может присутствовать несколько чисел и все они могут находится в разных местах строки. Вот пример:
PRODUCT METALIC BALL SIZE 16 MM (0.629 IN)
PRODUCT WITH AN EYELET BALL SIZE 14 MM (0.551 IN)
PRODUCT METALIC BALL SIZE 9 MM (0.354 IN)
PRODUCT METALIC BALL SIZE 13 MM (0.511 IN)
PRODUCT WITH AN EYELET BALL SIZE 9 MM (0.354 IN)
PRODUCT WITH AN EYELET BALL SIZE 10 MM (0.393 IN)

При стандартной сортировке (ORDER BY name ASC) я получаю следующий список:
PRODUCT METALIC BALL SIZE 13 MM (0.511 IN)
PRODUCT METALIC BALL SIZE 16 MM (0.629 IN)
PRODUCT METALIC BALL SIZE 9 MM (0.354 IN)
PRODUCT WITH AN EYELET BALL SIZE 10 MM (0.393 IN)
PRODUCT WITH AN EYELET BALL SIZE 14 MM (0.551 IN)
PRODUCT WITH AN EYELET BALL SIZE 9 MM (0.354 IN)

Товары сортируются по первым буквам, которые до цифр, а потом идет классическая строковая сортировка чисел: 13, 16, 9 и 10, 14, 9. Сравнение происходит только по первой цифре, поэтому 9 оказывается после 10 и выше.

В чем проблема: в том, что эти числа могут находится в любом месте строки, они могут быть в полукруглых скобках, или нет. Поскольку числа в названии товара могут находится где угодно, то отпадают все варианты с SUBSTRING_INDEX. Так же мне даже в голову не приходит, смогут ли тут помочь регулярные выражения. Получается, что нужно создать сортировку, которая будет по-очереди брать каждое слово после пробела и сравнивать его как строку или как число.

На данный момент я решил вопрос, как мне кажется, зверским костылем. При выборке товара я сделал вырезку скобок и создал еще одну переменную name_order - это чтобы в будущем не пришлось еще раз избавляться от скобок:
SELECT name, REPLACE(REPLACE(name, '(', ''), ')', '') as name_order FROM product

Далее я создал функцию SPLIT_STR, которая будет резать переменную по пробелу. Ну и последнее, и самое страшное - это разрезка названия товара на отдельные слова и числа, приведение каждого элемента этого "массива" к числу через CAST, и как следствие, сортировка по огромному количеству переменных:
SELECT name, REPLACE(REPLACE(name, '(', ''), ')', '') as name_order FROM product ORDER BY
CAST(SPLIT_STR(name_order, ' ', 1) AS SIGNED), SPLIT_STR(name_order, ' ', 1),
CAST(SPLIT_STR(name_order, ' ', 2) AS SIGNED), SPLIT_STR(name_order, ' ', 2),
CAST(SPLIT_STR(name_order, ' ', 3) AS SIGNED), SPLIT_STR(name_order, ' ', 3),
CAST(SPLIT_STR(name_order, ' ', 4) AS SIGNED), SPLIT_STR(name_order, ' ', 4),
CAST(SPLIT_STR(name_order, ' ', 5) AS SIGNED), SPLIT_STR(name_order, ' ', 5),
CAST(SPLIT_STR(name_order, ' ', 6) AS SIGNED), SPLIT_STR(name_order, ' ', 6),
CAST(SPLIT_STR(name_order, ' ', 7) AS SIGNED), SPLIT_STR(name_order, ' ', 7),
CAST(SPLIT_STR(name_order, ' ', 8) AS SIGNED), SPLIT_STR(name_order, ' ', 8),
CAST(SPLIT_STR(name_order, ' ', 9) AS SIGNED), SPLIT_STR(name_order, ' ', 9),
CAST(SPLIT_STR(name_order, ' ', 10) AS SIGNED), SPLIT_STR(name_order, ' ', 10),
CAST(SPLIT_STR(name_order, ' ', 11) AS SIGNED), SPLIT_STR(name_order, ' ', 11),
CAST(SPLIT_STR(name_order, ' ', 12) AS SIGNED), SPLIT_STR(name_order, ' ', 12),
name ASC

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

Внимание вопрос: может быть у кого-то есть более корректное и адекватное решение задачи? Собственный опыт или хотя бы мысли, как сделать такой же функционал, но более аккуратно и красиво?

Буду благодарен за любые мысли! И заранее спасибо ))
  • Вопрос задан
  • 4259 просмотров
Пригласить эксперта
Ответы на вопрос 1
@vdem
Сделайте отдельный столбец (или пару-тройку столбцов), в который заносите цифровую харектиристику товара, заполните его регуляркой, и сортируйте по имени и этому столбцу. Да, не идеальное решение, но лучшего я тут не вижу, и сам бы поступил так.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы