我有一个包含软件发行版本的数据库,我希望能够撤回所有版本,这些版本大于当前版本,按版本号排序。但是,版本以自定义(但标准)的方式排序 - 从alpha版本到beta版本到main版本到补丁。所以这是一个排序的例子:
100a1
100a4
100b1
100
100p1
101
101p3
etc.
是否可以形成一个SQL查询,根据自定义顺序拉回此数据,或者>只适用于整数和日期等给定的排序?我正在使用MSSQL,如果这有任何区别。
答案 0 :(得分:1)
只要您能够实际描述排序应该如何工作,当然。
两种基本方法是:
order by left([Version] + '__', 5)
之类的内容。从更复杂的值中生成单个整数也可以。order by
中的所有值。这是在SQL中处理此问题的更惯用的方式 - 基本上,当您在逻辑上使用101p1
时,为什么要使用一个值101, p, 1
?在SQL中解析有点棘手,因为SQL实际上是为规范化数据集设计的 - 而且你有效地将多个值存储在一列中。但是,如果你的规则不是太复杂,那么这仍然是可行的。不过,它不会非常漂亮:D
对于固定长度值,这当然非常简单 - 这相当于使用例如001p01
作为文件系统中的文件名 - 字母顺序是正确的顺序。然后,您可以在整个值上使用order by
,或者根据substring
将其拆分为多个部分。对于带分隔符的值,它有点丑陋,但仍然非常简单 - 1.p.1
可以相对容易地拆分,然后您可以按顺序按每个部分排序。
然而,你的系统似乎比机器更适合人类 - 没有真正的提示可以遵循。基本上,似乎你正在寻找“数字,字母,数字......将数字视为数字,将字母视为字母”的模式。在T-SQL中处理这实际上非常棘手。引入CLR的帮助,特别是正则表达式可能是值得的 - 尽管如此,我不确定你是否能够处理无限量的数字/字母组。 / p>
到目前为止,最简单的方法似乎是简单地将版本列分成多个列,每个列只有一个值 - 类似MajorVersion, Level, Revision
或类似的内容,对应101, Alpha, 3
。
答案 1 :(得分:0)
我假设前三个是数字。
select * from tablename order by convert(int,left(Columnname,3))
答案 2 :(得分:0)
这是我的代码示例。不是最短的,但它拥有许多演示输入/输出,如果你理解我想要的东西,可以进一步简化。
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
这是我的意见:
version
----------
100a1
100a4
100b1
100p1
100
101
101p3
这就是结果:
version
----------
100a1
100a4
100b1
100
100p1
101
101p3
反正。我建议将这些值拆分为单独的列。它会让你的生活更轻松。 : - )