I've got a database that contains release versions of software and I want to be able to pull back all versions that are greater than the current version, ordered by version number. However, the releases are sorted in a custom (but standard) way - from alpha version to beta version to main release to patch. So here's an example of the ordering:
100a1
100a4
100b1
100
100p1
101
101p3
etc.
Is it possible to form an SQL query that pulls back this data given the custom ordering or does > only work for given orderings like integers and dates? I'm working with MSSQL if that makes any difference.
As long as you can actually describe how the ordering is supposed to work, sure.
The two basic approaches are:
order by left([Version] + '__', 5)
. Making a single integer out of the more complex value also works. order by
, in any order you want. This is the more idiomatic way of handling this in SQL - basically, why are you using one value 101p1
when you're logically working with 101, p, 1
? Parsing is a bit tricky to handle in SQL, because SQL really is designed for normalized data sets - and you're effectively storing multiple values in one column. If your rules aren't too complicated, though, this should still be doable. It's not going to be awfully pretty, though :D
For fixed length values, this is pretty simple, of course - that's the equivalent of using eg 001p01
as filenames in the file system - the alphabetical ordering is the correct ordering. You could then simply use order by
on the whole value, or split it into parts based on substring
s. For values with separators, it's a bit uglier, but still pretty easy - 1.p.1
can be split relatively easily, and then you can order by each of the parts in sequence.
However, your system seems to be a better fit for humans than machines - there's no real hints to follow. Basically, it seems that you're looking at a pattern of "numbers, letters, numbers... treat numbers as numbers, and letters as letters". This is actually quite tricky to handle in T-SQL. It might be worth it to bring in the help of the CLR, and regular expressions in particular - I'm not sure if you'll be able to handle this in general for an unlimited amount of number/letter groups anyway, though.
The simplest way by far seems to be to simply separate the version column into multiple columns, each with just one value - something like MajorVersion, Level, Revision
or something like that, corresponding to 101, Alpha, 3
.
我认为前3个是数字。
select * from tablename order by convert(int,left(Columnname,3))
Here is my code example. Not the shortest one but it holds many demo input/output and can be further simplified if you understand what I want.
CREATE TABLE #versions(version nvarchar(10))
INSERT INTO #versions(version)
VALUES(N'100a1'),(N'100a4'),(N'100b1'),(N'100p1'),(N'100'),(N'101'),(N'101p3')
-- Just an example using substrings etc. how to get the
SELECT version,
SUBSTRING(version,1,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)-1
ELSE LEN(version)
END
) as version_number,
SUBSTRING(version,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)
ELSE 0
END, PATINDEX(N'%[0-9]%',
SUBSTRING(version,1,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)-1
ELSE LEN(version)
END
)
)
) as version_suffix,
SUBSTRING(version,
PATINDEX(N'%[a-z]%',
SUBSTRING(version,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)
ELSE LEN(version)
END, LEN(version)
)
),
PATINDEX(N'%[0-9]%',
SUBSTRING(version,1,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)-1
ELSE LEN(version)
END
)
)
) as version_sub
FROM #versions
-- Now your code:
;WITH vNumber AS(
SELECT version,SUBSTRING(version,1,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)-1
ELSE LEN(version)
END
) as version_number
FROM #versions
), vSuffix AS(
SELECT version, SUBSTRING(version,
CASE
WHEN PATINDEX(N'%[a-z]%',version) > 0
THEN PATINDEX(N'%[a-z]%',version)
ELSE LEN(version)
END, LEN(version)
) as version_suffix
FROM #versions
)
SELECT dat.version
FROM (
SELECT vn.version, vn.version_number,
CASE
SUBSTRING(vn.version,
CASE
WHEN PATINDEX(N'%[a-z]%',vn.version) > 0
THEN PATINDEX(N'%[a-z]%',vn.version)
ELSE 0
END, 1
)
WHEN N'a' THEN 1
WHEN N'b' THEN 2
WHEN N'' THEN 3
WHEN N'p' THEN 4
END as version_suffix,
SUBSTRING(vn.version,
PATINDEX(N'%[a-z]%',
vs.version_suffix
),
PATINDEX(N'%[0-9]%',
SUBSTRING(vn.version,1,
CASE
WHEN PATINDEX(N'%[a-z]%',vn.version) > 0
THEN PATINDEX(N'%[a-z]%',vn.version)-1
ELSE LEN(vn.version)
END
)
)
) as version_sub
FROM vNumber as vn
INNER JOIN vSuffix as vs
ON vn.version = vs.version
) AS dat
ORDER BY dat.version_number, dat.version_suffix, dat.version_sub
DROP TABLE #versions
This is my input:
version
----------
100a1
100a4
100b1
100p1
100
101
101p3
And this is the result:
version
----------
100a1
100a4
100b1
100
100p1
101
101p3
Anyway. I would suggest to split those values into separate columns. It will make your live much easier. :-)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.