substring_index пропускает разделитель справа

У меня есть таблица 'car_purchases' со столбцом 'description'. Столбец представляет собой строку, которая включает в себя имя инициала, за которым следуют точка, пробел и фамилия. Пример столбца Описание

'Автомобиль, купленный Дж. Блоу'

Я использую функцию substring_index для извлечения буквы, предшествующей "." в строке столбца. Вот так:

SELECT
Description,
SUBSTRING_INDEX(Description, '.', 1) as TrimInitial,
SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1) as trimmed,
length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length
from car_purchases;

Я назову этот запрос 1.

картина набора результатов (Результат 1) выглядит следующим образом

Как видите, проблема в том, что столбец "обрезается" в операторе выбора начинает отсчитывать второй разделитель вместо первого справа и выдает результат "по J" вместо просто "J". Кроме того, столбец длины указывает, что длина строки равна 5, а не 4, поэтому WTF?

Однако, когда я выполняю следующее утверждение выбора;

select SUBSTRING_INDEX(
SUBSTRING_INDEX('Car purchased by J. Blow', '.', 1),' ', -1); -- query 2

Результат = "J" как "Результат 2".

Как видно из результата 1, строка в столбце "Описание" в точности (насколько я могу судить) совпадает со строкой из "Результата 2". Но когда substring_index выполняется для столбца (а не только для самой строки), результат игнорирует первый разделитель и выбирает строку из 2-го разделителя справа от строки.

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

В столбце "длина" запроса 1 есть аномалия, где, если я изменю функцию длины на функцию char_length, вот так:

select length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length -- result = 5

select char_length(SUBSTRING_INDEX(
SUBSTRING_INDEX(Description, '.', 1),' ', -1)) as length -- result = 4

Может ли кто-нибудь объяснить мне, почему вышеприведенное предложение выбора даст 2 разных результата? Я думаю, что это причина, почему я не получаю желаемый результат.

Но для ясности, мой желаемый результат - получить "J", а не "J".

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

Приветствия Игроки!!!!

1 ответ

CHAR_LENGTH возвращает длину в символах, поэтому строка с 4 2-байтовыми символами вернет 4. LENGTH однако возвращает длину в байтах, поэтому строка с 4 2-байтовыми символами вернула бы 8. Расхождение в ваших результатах (включая SUBSTRING_INDEX) говорит, что "пространство" между by а также J на самом деле это не однобайтовый пробел (ASCII 0x20), а двухбайтовый символ, который выглядит как пробел. Чтобы обойти это, вы можете попробовать заменить все символы Юникода пробелами, используя CONVERT а также REPLACE, В этом примере у меня есть en-space символ Юникода в строке между by а также J, CONVERT меняет это на ? и REPLACE затем преобразует это в пространство:

SELECT SUBSTRING_INDEX( SUBSTRING_INDEX("Car purchased by J. Blow", '.', 1),' ', -1)

Выход:

by J

С CONVERT а также REPLACE:

SELECT SUBSTRING_INDEX( SUBSTRING_INDEX(REPLACE(CONVERT("Car purchased by J. Blow" USING ASCII), '?', ' '), '.', 1),' ', -1)

Выход

J

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

 SELECT SUBSTRING_INDEX( SUBSTRING_INDEX(REPLACE(CONVERT(description USING ASCII), '?', ' '), '.', 1),' ', -1)

Демо на DBFiddle

Другие вопросы по тегам