SQL сортировка по версии «число», строка различной длины - PullRequest
27 голосов
/ 09 февраля 2009

Я пытаюсь создать запрос SQL, который упорядочит результаты по номеру версии (например, 1.1, 4.5.10 и т. Д.)

Вот что я попробовал:

SELECT * FROM Requirements 
    WHERE Requirements.Release NOT LIKE '%Obsolete%' 
    ORDER BY Requirements.ReqNum

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

Когда я получу результаты обратно, я получу следующий заказ:

1.1
1.10
1.11
1.3

Как мне написать запрос, который будет сортировать по лексикографическому порядку?

... или

Как правильно отсортировать данные?

Спасибо за ввод заранее!

Ответы [ 21 ]

24 голосов
/ 11 июня 2015

В PostgreSQL вы можете сделать:

SELECT * FROM Requirements
ORDER BY string_to_array(version, '.')::int[];

Этот последний ::int[] позволяет преобразовать строковые значения в целые числа, а затем сравнить как таковые.

24 голосов
/ 09 февраля 2009

Для достижения наилучших результатов, рефакторинг хранения номера версии, чтобы каждый раздел имел свой собственный столбец: MajorVersion, MinorVersion, Revision, Build Тогда проблема порядка вдруг становится тривиальной. Вы также можете построить вычисляемый столбец для простого извлечения полной строки.

13 голосов
/ 13 ноября 2012
SELECT * FROM Requirements 
WHERE Requirements.Release NOT LIKE '%Obsolete%' 
ORDER BY cast('/' + replace(Requirements.ReqNum , '.', '/') + '/' as hierarchyid);
7 голосов
/ 12 июля 2016

Небольшое отклонение от ответа @ vuttipong-l (T-SQL)

SELECT VersionNumber
FROM (
SELECT '6.1.3' VersionNumber UNION
SELECT '6.11.3' UNION
SELECT '6.2.3' UNION
SELECT '6.1.12' 
) AS q
ORDER BY cast('/' + VersionNumber + '/' as hierarchyid)

Работает в SQL Server начиная с 2008 года, точки в порядке в строковом представлении столбца hierarchyid, поэтому нам не нужно заменять их косыми чертами. Цитата из документа:

Сравнение выполняется путем сравнения целочисленных последовательностей, разделенных по точкам в словарном порядке.

Однако есть одно предостережение: сегменты версий не должны начинаться с нуля.

4 голосов
/ 10 февраля 2009

Если вы находитесь на земле SQL Server ...

DECLARE @string varchar(40)
SET @string = '1.2.3.4'
SELECT PARSENAME(@string, 1), PARSENAME(@string, 2), PARSENAME(@string, 3), PARSENAME(@string, 4)

Результаты: 4, 3, 2, 1

Полезно для анализа IP-адресов и других пунктирных элементов, таких как номер версии. (Вы также можете использовать REPLACE () для преобразования элементов в точечную запись ... например 1-2-3-4 -> 1.2.3.4)

3 голосов
/ 09 февраля 2009

Если вы не перепроектируете таблицу, как разумно предлагает Джоэл Кохорн, то вам нужно переформатировать номера версий в строку, которая сортируется по вашему желанию, например,

  • 1.1 -> 0001.0001.0000
  • 162.1.11 -> 0162.0001.0011

Это может быть сделано с помощью функции или с помощью вычисляемого / виртуального столбца, если они есть в вашей СУБД. Затем вы можете использовать эту функцию или столбец в предложении ORDER BY.

3 голосов
/ 09 февраля 2009

Следующая функция будет брать номер версии и форматировать каждый уровень до трех цифр:

Использование:

select * from TableX order by dbo.fn_VersionPad(VersionCol1)

Функция:

CREATE FUNCTION [dbo].[fn_VersionPad]
(
    @version varchar(20)
)
RETURNS varchar(20)
AS
BEGIN
    /*
        Purpose:  Pads multi-level Version Number sections to 3 digits
        Example:  1.2.3.4
        Returns:  001.002.003.004
    */

    declare @verPad varchar(20)
    declare @i int
    declare @digits int

    set @verPad = ''

    set @i = len(@version)
    set @digits = 0

    while @i > 0
    begin
        if (substring(@version, @i, 1) = '.')
        begin
            while (@digits < 3)
            begin
                -- Pad version level to 3 digits
                set @verPad = '0' + @verPad
                set @digits = @digits + 1
            end

            set @digits = -1
        end

        set @verPad = substring(@version, @i, 1) + @verPad

        set @i = @i - 1
        set @digits = @digits + 1
    end

    while (@digits < 3)
    begin
        -- Pad version level to 3 digits
        set @verPad = '0' + @verPad
        set @digits = @digits + 1
    end

    return @verPad
END
2 голосов
/ 09 февраля 2009

Вы можете разделить строку (вы уже знаете разделители: ".") С CHARINDEX / SUBSTR и ORDER BY различными частями. Делай это в функции или делай это по частям.

Это будет не красиво и не быстро: так что, если вам нужны быстрые запросы, следуйте за Тони или Джоэлом.

2 голосов
/ 06 декабря 2014

На PostgreSQL это не может быть проще:

SELECT ver_no FROM version ORDER BY string_to_array(ver_no, '.', '')::int[]

2 голосов
/ 28 октября 2011

НЕ ИСПОЛЬЗУЙТЕ КОД

Insert into @table
Select 'A1' union all
Select 'A3' union all
Select 'A5' union all
Select 'A15' union all
Select 'A11' union all
Select 'A10' union all
Select 'A2' union all
Select 'B2' union all
Select 'C2' union all
Select 'C22' union all
Select 'C221' union all
Select 'A7' 

Select cod from @table
Order by LEN(cod),cod 

Результат:

A1
A2
A3
A5
A7
B2
C2
A10
A11
A15
C22
C221

Это просто как:

Declare @table table(id_ int identity(1,1), cod varchar(10))

Insert into @table
Select 'A1' union all
Select 'A3' union all
Select 'A5' union all
Select 'A15' union all
Select 'A11' union all
Select 'A10' union all
Select 'A2' union all
Select 'A7' 

Select cod from @table
Order by LEN(cod),cod  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...