Я хочу перечислить (отсортированный список) все мои записи из атрибута streetNames в моей таблице / отношении Customers. например. Я хочу добиться следующего порядка:
Улица_1A
Улица_1B
Улица_2A
Улица_2B
Улица_12A
Улица_12Б
Простой порядок по streetNames выполнит лексическое сравнение, и тогда Street_12A и B появятся перед Street_2A / B, а это неверно. Можно ли решить эту проблему с помощью чистого SQL?
Какой бы ни была СУБД, попытка решить эту проблему без разделения данных на несколько полей (как предлагается в некоторых ответах) - безнадежное дело.


Выберите street_name из таблицыx заказать по udf_getStreetNumber (street_name)
в вашем udf_getStreetNumber - напишите свое бизнес-правило для удаления числа
РЕДАКТИРОВАТЬ
Я думаю, что теперь вы можете использовать функцию регулярного выражения в SQL Server. Я бы просто вычеркнул из ввода все нечисловые символы.
Что будет плохо работать для чего-то большего, чем несколько сотен строк ... лучше разделить поля, даже если это вычисляемый столбец с использованием той же функции, которая может быть сохранена и проиндексирована
Данные такие, какие есть ... Он не просил переделать свою схему. Мне приходилось использовать такие udf-файлы в миллионах строк, и он работает быстро и без проблем.
@mson, Запуск udf для миллионов строк - это реальная проблема производительности, если только вы не используете "встроенный" udf ... Это потому, что (кроме встроенных udf) udf нужно перекомпилировать для каждого выполнения (миллион раз, если вы запускаете его для выбора миллиона строк ...)
@Charles - Как бы это экономическое обоснование было записано иначе, чем в виде скалярного udf?
Да, это возможно! Но определенно неинтересно! Если вы найдете здесь кого-то, готового потратить несколько часов на запись и тестирование SP, который разделит ваши streetNames на комбинацию streetName + streetNumber, сообщите мне его имя: я отправлю ему несколько задач, где, как я думал, мне пришлось заплатить, чтобы получить проделанная работа.
Кстати, нельзя ли разделить свои данные на 2 поля: одно «streetName» только с названием улицы и новое поле «buildingNumber»? (Не называйте это «streetNumber», так как в некоторых странах / городах улицам даются номера).
Я уверен, что вы могли бы разделить поле streetName на разные части с помощью чего-то вроде substr (streetName, 1, find ("", streetName)) только для улицы и так далее. Но это будет довольно беспорядочно, и ему придется иметь дело со всеми видами особых случаев (без номера дома, номер дома без добавления) или международными проблемами (в США адреса обычно похожи на 1 Street).
Но если вы хотите, чтобы сортировка выполнялась так, как вы описали, и это является важным требованием, было бы лучше смоделировать ваше streetName в трех частях, то есть улице (например, «Улица»), house_number (например, 1, 2, 12), house_num_addition ( например, «А», «Б»). Тогда сортировка в SQL становится тривиальной.
Почему вы думаете, что этот номер - это номер дома, а не, как он заявляет в задаче, часть названия улицы?
Улицы не могут быть легко разбиты на 3 компонента. Вы обнаружите, что сочетание международных, сельских маршрутов, военных и сумасшедших названий улиц нарушает ваше правило.
Если у вас есть доступ для записи в базу данных, я бы действительно рекомендовал преобразовать все это, чтобы использовать 3 отдельных поля, а затем использовать их соответствующим образом. Таким образом, вы могли бы сделать это даже в PHP (да, это займет некоторое время, но это произойдет только один раз). Это может быть неприятно, если у вас большая база кода, и вам нужно проверять все запросы с помощью этой таблицы, но в конечном итоге это окупится позже. Например, это значительно упростит поиск по адресу.
Надежный способ сделать это (надежный с точки зрения «правильной сортировки данных», а не «решения вашей общей проблемы») - разделить данные на название улицы и номер дома и сортировать их по отдельности. Но для этого нужно знать, где начинается номер дома. И это сложная часть - сделать предположение, которое лучше всего соответствует вашим данным.
Вы должны использовать что-то вроде следующего для рефакторинга ваших данных и с этого момента хранить номер дома в отдельном поле. Когда дело доходит до сортировки больших наборов данных, все эти манипуляции со строками не очень эффективны.
Предположим, что это последнее слово в названии улицы, и оно содержит номер:
DECLARE @test TABLE
(
street VARCHAR(100)
)
INSERT INTO @test (street) VALUES('Street')
INSERT INTO @test (street) VALUES('Street 1A')
INSERT INTO @test (street) VALUES('Street1 12B')
INSERT INTO @test (street) VALUES('Street 22A')
INSERT INTO @test (street) VALUES('Street1 200B-8a')
INSERT INTO @test (street) VALUES('')
INSERT INTO @test (street) VALUES(NULL)
SELECT
street,
CASE
WHEN LEN(street) > 0 AND CHARINDEX(' ', REVERSE(street)) > 0
THEN CASE
WHEN RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1) LIKE '%[0-9]%'
THEN LEFT(street, LEN(street) - CHARINDEX(' ', REVERSE(street)))
END
END street_part,
CASE
WHEN LEN(street) > 0 AND CHARINDEX(' ', REVERSE(street)) > 0
THEN CASE
WHEN RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1) LIKE '%[0-9]%'
THEN RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1)
END
END house_part,
CASE
WHEN LEN(street) > 0 AND CHARINDEX(' ', REVERSE(street)) > 0
THEN CASE
WHEN RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1) LIKE '%[0-9]%'
THEN CASE
WHEN PATINDEX('%[a-z]%', LOWER(RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1))) > 0
THEN CONVERT(INT, LEFT(RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1), PATINDEX('%[^0-9]%', LOWER(RIGHT(street, CHARINDEX(' ', REVERSE(street)) - 1))) - 1))
END
END
END house_part_num
FROM
@test
ORDER BY
street_part,
house_part_num,
house_part
Это предполагает следующие условия:
REPLACE(street, ' - ', '-') для предварительной очистки общих шаблонов).Я думаю, что ваши предполагаемые ограничения относительно числа не пройдут первые 10 строк!
Потому что у вас будут строки без чисел, строки с числами, строки с числами + текст (A, B, C), строки, в которых число будет в начале поля и т. д.
строки с числами типа 292-296 и т. д.
Если все значения в столбце streetNames соответствуют шаблону StreetName- пробел - StreetNumber
где StreetName может содержать другие пробелы, но StreetNumber НЕ МОЖЕТ, тогда это будет работать:
Declare @T Table (streetName VarChar(50))
Insert @T(streetName) Values('Street 1A')
Insert @T(streetName) Values('Street 2A')
Insert @T(streetName) Values('Street 2B')
Insert @T(streetName) Values('Street 12A')
Insert @T(streetName) Values('Another Street 1A')
Insert @T(streetName) Values('Another Street 4A')
Insert @T(streetName) Values('a third Street 12B')
Insert @T(streetName) Values('a third Street 1C')
Select * From @T
Order By Substring(StreetName, 0, 1 + len(StreetName) - charIndex(' ', reverse(StreetName))),
Cast(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)),
Case When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 5)) = 1 Then 5
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 4)) = 1 Then 4
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 3)) = 1 Then 3
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 2)) = 1 Then 2
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 1)) = 1 Then 1
End) as Integer),
Substring(StreetName, len(StreetName) - charIndex(' ', reverse(StreetName)) +
Case When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 5)) = 1 Then 5
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 4)) = 1 Then 6
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 3)) = 1 Then 5
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 2)) = 1 Then 4
When IsNumeric(Substring(StreetName, 2 + len(StreetName) - charIndex(' ', reverse(StreetName)), 1)) = 1 Then 3
End, Len(StreetName))
Для записи: он называется Естественный порядок сортировки, а есть Кодирующая статья ужасов в теме.
Я предполагаю, что вы можете сделать это в SQL, используя часть кода, показанного здесь, но это всегда будет происходить в каждом конкретном случае.
Единственный интерес на весь вопрос - получить ответ со ссылкой на статью. Спасибо!
Какая СУБД? Некоторые предоставляют нестандартные способы изменения порядка сортировки