2016-03-15 30 views
0

我有一个表格,其中几个报表实体存储其数据的多个版本(由整数版本号索引)。我创建该表仅选择最新版本的一个观点:Oracle SQL:选择最大减1除最低(获得以前的数据版本)

SELECT * FROM MYTABLE NATURAL JOIN 
(
    SELECT ENTITY, MAX(VERSION) VERSION FROM MYTABLE 
    GROUP BY ENTITY 
) 

现在我想创建另一个观点,即始终选择最新的前一个版本进行比较。我想过为此使用MAX() - 1(见下文),它通常有效,但问题是这排除了仅报告一个版本的实体的条目。

SELECT * FROM MYTABLE NATURAL JOIN 
(
    SELECT ENTITY, MAX(VERSION) - 1 VERSION FROM MYTABLE 
    GROUP BY ENTITY 
) 

编辑:为了清楚起见,如果只有一个版本可用,我希望它报告一个。作为一个例子,考虑如下表:

ENTITY VERSION VALUE1 
10000 1  10 
10000 2  11 
12000 1  50 
14000 1  15 
14000 2  16 
14000 3  17 

现在我希望得到我的查询是

ENTITY VERSION VALUE1 
10000 1  10 
12000 1  50 
14000 2  16 

但我目前的查询,为12000项落下。

+2

那么如果只有一个版本应该怎么办?报告为空或零,还是第一个(唯一)版本?在问题中添加一些样本数据和预期输出可能会澄清事情。版本可以被删除 - 所以如果你有版本8,可能没有版本7? –

+1

请勿使用'NATURAL JOIN'。这是一个等待发生的错误。 –

+0

@GordonLinoff我正在使用'NATURAL JOIN',因为'INNER JOIN'给了我不需要的其他字段(如VALUE1_1)。你会推荐什么? – Chris7b

回答

0

你可能避免与分析查询自联接:

SELECT ENTITY, VERSION, LAST_VERSION 
FROM (
    SELECT ENTITY, VERSION, 
    NVL(LAG(VERSION) OVER (PARTITION BY ENTITY ORDER BY VERSION), VERSION) AS LAST_VERSION, 
    RANK() OVER (PARTITION BY ENTITY ORDER BY VERSION DESC) AS RN 
    FROM MYTABLE 
) 
WHERE RN = 1; 

那找到目前和以前的版本,所以你可以有一个单一的观点,如果你想要得到两个。

LAG(VERSION) OVER (PARTITION BY ENTITY ORDER BY VERSION)获取每个实体的先前版本号,对于第一个录制的版本将为空;因此在这种情况下,NVL被用于再次采用当前版本。 (您也可以使用更多标准COALESCE功能)。如果您有任何版本号,这也可以弥补缺陷。

RANK() OVER (PARTITION BY ENTITY ORDER BY VERSION DESC)为每个实体/版本对分配一个连续编号,DESC表示最高版本排名为1,次高为2等。我假定您不会有实体的重复版本 - 您可以使用DENSE_RANK并决定如何打破关系,但这似乎不太可能。

为你的数据,你可以看到,随着生产:

SELECT ENTITY, VERSION, VALUE1, 
    LAG(VERSION) OVER (PARTITION BY ENTITY ORDER BY VERSION) AS LAG_VERSION, 
    NVL(LAG(VERSION) OVER (PARTITION BY ENTITY ORDER BY VERSION), VERSION) AS LAST_VERSION, 
    RANK() OVER (PARTITION BY ENTITY ORDER BY VERSION DESC) AS RN 
FROM MYTABLE 
ORDER BY ENTITY, VERSION; 

    ENTITY VERSION  VALUE1 LAG_VERSION LAST_VERSION   RN 
---------- ---------- ---------- ----------- ------------ ---------- 
    10000   1   10      1   2 
    10000   2   11   1   1   1 
    12000   1   50      1   1 
    14000   1   15      1   3 
    14000   2   16   1   1   2 
    14000   3   17   2   2   1 

所有这一切都在一个内嵌视图进行,与外部查询只返回那些排名第一 - 也就是最高的行版本为每个实体。

您也可以包括VALUE1列,例如,只是为了显示前值:

SELECT ENTITY, VERSION, VALUE1 
FROM (
    SELECT ENTITY, 
    NVL(LAG(VERSION) OVER (PARTITION BY ENTITY ORDER BY VERSION), VERSION) AS VERSION, 
    NVL(LAG(VALUE1) OVER (PARTITION BY ENTITY ORDER BY VERSION), VALUE1) AS VALUE1, 
    RANK() OVER (PARTITION BY ENTITY ORDER BY VERSION DESC) AS RN 
    FROM MYTABLE 
) 
WHERE RN = 1 
ORDER BY ENTITY; 

    ENTITY VERSION  VALUE1 
---------- ---------- ---------- 
    10000   1   10 
    12000   1   50 
    14000   2   16 
+0

太好了,谢谢所有的回复!我会接受他的回答,因为它避免了我原来的'NATURAL JOIN',这显然是不好的练习。 – Chris7b

+0

@ Chris7b - 这里有一些关于不使用自然连接的理由的讨论(http://stackoverflow.com/q/8696383/266304)。您的自联接查询并不真正容易受到模式更改的影响 - 比任何其他连接都要多 - 但这不是一个好习惯。如果您不使用'select *',那么您可以使用内部连接,这是避免的另一个坏习惯。但在这种情况下,根本不需要连接。 –

+0

感谢您的额外信息!阅读了一些答案后,我再次对自然参加感到更加自在。但是我确实懒惰了*(实际的桌子有20多个字段,在我的防守中))。 – Chris7b

0

你可以加入到MAX(VERSION)的情况下,只有一个VERSIONENTITY值:

SELECT * 
FROM MYTABLE 
NATURAL JOIN 
(
    SELECT ENTITY, 
     CASE 
      WHEN MAX(VERSION) <> MIN(VERSION) THEN MAX(VERSION) - 1 
      ELSE MAX(VERSION) 
     END VERSION 
    FROM MYTABLE 
    GROUP BY ENTITY 
) 
+0

太好了,谢谢!它完美地完成了这项工作,但我接受了另一个答案,因为建议完全避免使用NATURAL JOIN。 – Chris7b

1

可以制定任务为:获取每个实体,并从这些取每个实体的最低版本最高的两个可用的版本。您可以用ROW_NUMBER排列记录来确定n个最高版本。

select entity, min(version) 
from 
(
    select 
    entity, 
    version, 
    row_number() over (partition by entity order by version desc) as rn 
    from mytable 
) 
where rn <= 2 
group by entity; 

此作品无论是否有纪录只有一个或两个或更多的实体,无论任何可能的差距的。