Как получить максимальное значение столбца номера версии (varchar) в T-SQL

У меня есть таблица, определенная следующим образом:

Column:  Version     Message
Type:    varchar(20) varchar(100)
----------------------------------
Row 1:    2.2.6       Message 1
Row 2:    2.2.7       Message 2
Row 3:    2.2.12      Message 3
Row 4:    2.3.9       Message 4
Row 5:    2.3.15      Message 5

Я хочу написать запрос T-Sql, который получит сообщение о номере версии MAX, где столбец «Версия» представляет номер версии программного обеспечения. То есть 2.2.12 больше, чем 2.2.7, а 2.3.15 больше, чем 2.3.9 и т. д. К сожалению, я не могу придумать простого способа сделать это без использования CHARINDEX или какой-либо другой сложной логики, подобной расщеплению. . Выполнение этого запроса:

SELECT MAX(Version) FROM my_table

даст ошибочный результат:

2.3.9

Когда на самом деле должно быть 2.3.15. Любые яркие идеи, которые не становятся слишком сложными?


person Ogre Psalm33    schedule 16.06.2010    source источник


Ответы (2)


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

Select TOP 1 Major, Minor, Build
From ( ...derived crosstab query )
Order By Major Desc, Minor Desc, Build Desc

На самом деле, другой способ — использовать функцию PARSENAME, предназначенную для разделения имен объектов:

Select TOP 1 Version
From Table
Order By Cast(Parsename( Z.Version , 3 ) As Int) Desc
    , Cast(Parsename( Z.Version , 2 ) As Int) Desc
    , Cast(Parsename( Z.Version , 1 ) As Int) Desc
person Thomas    schedule 16.06.2010
comment
+1: OP необходимо изменить модель данных для желаемой функциональности. - person OMG Ponies; 17.06.2010
comment
Идея Parsename довольно остроумна, но я должен согласиться с OMG — дизайн таблицы не позволяет выполнить желаемый простой запрос. - person Philip Kelley; 17.06.2010
comment
Да, я понимаю, что становится очень просто, если моя модель данных отличается. Поддержание устаревшего кода иногда может быть такой головной болью! Тем не менее, я обязательно буду иметь в виду лучшее решение, если у меня будет возможность провести рефакторинг базы данных в этом приложении. В то же время... я согласен... хорошее использование Parsename! - person Ogre Psalm33; 17.06.2010
comment
@Томас. Хм, на самом деле, после тестирования на реальных данных, я понял, что ваш Order By перевернут. Добавьте 3.0.1 к этому набору данных, и он потерпит неудачу. Если вы заказываете по 'Cast(Parsename(Z.Version, 3) As Int) Desc, Cast(Parsename(Z.Version, 2) As Int) Desc, Cast(Parsename(Z.Version, 1) As Int) Desc' вместо этого он работает правильно. - person Ogre Psalm33; 17.06.2010
comment
@ Ogre Psalm33 - Так быть не должно. Вы хотите заказать по основному (1) описанию, второстепенному (2) описанию, сборке (3) описанию. Если вы сделаете это так, как вы предложили (Build Desc, Minor Desc, Major Desc), версия 1.2.99 появится первой перед, скажем, 2.2.15. - person Thomas; 17.06.2010
comment
@Thomas. Посетите страницу Parsename MSDN: msdn.microsoft.com/en- нас/библиотека/ms188006.aspx. Порядок чисел обратный тому, что вы ожидаете. Сначала мне это было непонятно, но поверьте, я проверил это на реальных данных :-). - person Ogre Psalm33; 17.06.2010
comment
@Ogre Psalm33 - OIC. Это мое плохо. Я тоже неправильно прочитал. Я поправлю свой пост, чтобы приспособиться. - person Thomas; 17.06.2010

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

Если стол маленький, не беда. Затем вы можете использовать своевременный рейтинг, используя функцию разделения или (ab) используя имя разбора, как предложил Томас.

person Remus Rusanu    schedule 16.06.2010
comment
Интересная идея, но, к сожалению, мои реальные данные довольно велики. - person Ogre Psalm33; 17.06.2010