sha*_*uar 3 oracle plsql oracle11g
我使用的是Oracle Database 11g企业版11.2.0.2.0版
我有一张表如下:
Table1:
Name Null Type
----------------- -------- -------------
NAME NOT NULL VARCHAR2(64)
VERSION NOT NULL VARCHAR2(64)
Table1
Name Version
---------------
A 1
B 12.1.0.2
B 8.2.1.2
B 12.0.0
C 11.1.2
C 11.01.05
Run Code Online (Sandbox Code Playgroud)
我希望输出为:
Name Version
---------------
A 1
B 12.1.0.2
C 11.01.05
Run Code Online (Sandbox Code Playgroud)
基本上,我想获得具有最高版本的每个名称的行.为此,我使用以下查询:
SELECT t1.NAME,
t1.VERSION
FROM TABLE1 t1
LEFT OUTER JOIN TABLE1 t2
on (t1.NAME = t2.NAME and t1.VERSION < t2.VERSION)
where t2.NAME is null
Run Code Online (Sandbox Code Playgroud)
现在't1.VERSION <t2.VERSION'仅适用于正常版本的情况,但在以下情况下:
B 12.1.0.2
B 8.2.1.2
Run Code Online (Sandbox Code Playgroud)
它失败了,我需要一个PL/SQL脚本来规范化版本字符串并将它们与更高的值进行比较.
你可以通过明智地使用REGEXP_SUBSTR()来做到这一点; 没有必要使用PL/SQL.
select *
from ( select a.*
, row_number() over (
partition by name
order by to_number(regexp_substr(version, '[^.]+', 1)) desc
, to_number(regexp_substr(version, '[^.]+', 2)) desc
, to_number(regexp_substr(version, '[^.]+', 3)) desc
, to_number(regexp_substr(version, '[^.]+', 4)) desc
) as rnum
from table1 a )
where rnum = 1
Run Code Online (Sandbox Code Playgroud)
这是一个演示的SQL小提琴.请注意我是如何将每个部分转换为数字以使其工作的.
但是,如果你将它们分成不同的列,主要版本,次要版本等,我就不能强调你的生活会变得多么容易.然后你可以有一个虚拟列将它们连接起来以确保你的导出始终是标准化的,如果你愿意的话.
例如,如果您创建了一个表,如下所示:
create table table1 (
name varchar2(64)
, major number
, minor number
, build number
, revision number
, version varchar2(200) generated always as (
to_char(major) || '.' ||
to_char(minor) || '.' ||
to_char(build) || '.' ||
to_char(revision)
)
Run Code Online (Sandbox Code Playgroud)
您的查询变得更容易理解; 也在SQL Fiddle中
select name, version
from ( select a.*
, row_number() over (
partition by name
order by major desc
, minor desc
, build desc
, revision desc ) as rnum
from table1 a )
where rnum = 1
Run Code Online (Sandbox Code Playgroud)