SQL-запрос (упорядочить по) - PullRequest
1 голос
/ 09 декабря 2008

Я хочу перечислить (отсортированный список) все мои записи из атрибута с названием streetNames в моей таблице / отношениях. например. Я хочу добиться следующего заказа:

Street_1A
Street_1B
Street_2A
Street_2B
Street_12A
Street_12B

Простой порядок по streetNames проведет лексическое сравнение, а затем Street_12A и B появятся перед Street_2A / B, и это неверно. Можно ли решить это с помощью чистого SQL?

Ответы [ 7 ]

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

Выберите название улицы из таблицы упорядочить по udf_getStreetNumber (street_name)

в вашем udf_getStreetNumber - напишите ваше бизнес-правило для удаления номера

EDIT

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

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

Для записи: он называется Порядок естественной сортировки , и есть Статья ужасов кодирования в теме.

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

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

Если у вас есть доступ для записи в базу данных, я бы действительно рекомендовал преобразовать все это, чтобы использовать 3 отдельных поля, а затем использовать их соответствующим образом. Таким образом, вы даже можете сделать это на PHP (да, это займет некоторое время, но это произойдет только один раз). Это может быть немного болезненно, если у вас большая кодовая база, вам нужно проверить все запросы с этой таблицей, но это в конечном итоге окупится позже. Например, это значительно упростит поиск по адресу.

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

Я уверен, что вы могли бы разделить поле streetName на его отдельные части с помощью чего-то вроде substr (streetName, 1, find ("", streetName)) только для улицы и так далее. Но это будет довольно грязно, и придется иметь дело со всеми видами особых случаев (без номера дома, номера дома без добавления) или с международными вопросами (в США адреса, как правило, похожи на 1-стрит).

Но если вы хотите выполнить сортировку, как вы описали, и это является важным требованием, было бы лучше смоделировать вас streetName из трех частей, то есть street (например, «Street»), house_number (например, 1, 2, 12) , house_num_addition (например, "A", "B"). Тогда сортировка становится тривиальной в SQL.

0 голосов
/ 09 декабря 2008

Если это так, что все значения в столбце 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))
0 голосов
/ 09 декабря 2008

Надежный способ сделать это (надежный с точки зрения «правильной сортировки данных», а не «решения вашей общей проблемы») состоит в том, чтобы разделить данные по названию улицы и номеру дома и отсортировать их обоих самостоятельно. , Но для этого нужно знать, где начинается номер дома. И это сложная часть - сделать предположение, которое наилучшим образом соответствует вашим данным.

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

Предполагая, что это последняя вещь в названии улицы, и она содержит число:

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

Это предполагает следующие условия:

  • адрес улицы может иметь номер дома
  • номер дома должен быть последним в адресе улицы (без "525 Monroe Av.")
  • номер дома должен начинаться с цифры для правильной сортировки
  • номер дома может быть диапазоном ("200-205"), это будет отсортировано ниже 200
  • номер дома не должен содержать пробелов или распознавания не удается (Когда вы просматриваете свои данные, вы можете применить что-то вроде REPLACE(street, ' - ', '-') для предварительной очистки общих шаблонов.)
  • все это все еще приближение, которое, безусловно, отличается от того, как оно будет выглядеть в телефонной книге, например
0 голосов
/ 09 декабря 2008

Да, это возможно! Но определенно не представляет интереса! Если вы найдете здесь кого-нибудь, готового потратить несколько часов на написание и тестирование SP, который разделит ваши streetNames на комбинацию streetName + streetNumber, дайте мне его имя: я отправлю ему несколько проблем, где я думал, что должен был заплатить, чтобы получить проделанная работа.

Кстати, разве вы не можете разделить ваши данные на 2 поля: одно «streetName», содержащее только название улицы, и новое поле «buildingNumber»? (Избегайте называть это 'streetNumber', так как в некоторых странах / городах улицы имеют номера).

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