首页 > 解决方案 > 多列的 Oracle SQL 'KEEP' 和一列的 'KEEP' 和其余的 GROUP BY 之间有区别吗?

问题描述

我刚刚在 Oracle SQL 中学习 KEEP,但我似乎找不到解释为什么他们的示例在所有未编入索引的列中使用 KEEP 的文档。

我有一张有 5 列的表

PERSON_ID | BRANCH | YEAR | STATUS | TIMESTAMP  
123456    | 0001   | 2017 | 1      | 1-1-2017   (ROW 1)  
123456    | 0001   | 2017 | 2      | 2-1-2017   (ROW 2)  
123456    | 0002   | 2017 | 3      | 3-1-2017   (ROW 3)  
123456    | 0001   | 2017 | 2      | 4-1-2017   (ROW 4)  
123456    | 0001   | 2018 | 2      | 1-1-2018   (ROW 5)  
123456    | 0001   | 2018 | 3      | 2-1-2018   (ROW 6)  

我想按人、分支和年份返回最新时间戳的行,所以第 3、4 和 6 行。

RESULTS    
PERSON_ID | BRANCH | YEAR | STATUS | TIME_STAMP  
123456    | 0002   | 2017 | 3      | 3-1-2017   (ROW 3)  
123456    | 0001   | 2017 | 2      | 4-1-2017   (ROW 4)  
123456    | 0001   | 2018 | 3      | 2-1-2018   (ROW 6)  

为了得到整行,我通常会写这样的东西:

SELECT * 
FROM STATUS_TABLE a
WHERE a.TIME_STAMP = 
    (
    SELECT MAX(sub.TIME_STAMP) 
    FROM STATUS_TABLE sub
    WHERE a.PERSON_ID = sub.PERSON_ID
        AND a.YEAR = sub.YEAR
        AND a.BRANCH = sub.BRANCH
    )

但我正在学习我可以这样写:

SELECT 
    a.PERSON_ID, 
    a.YEAR, 
    a.BRANCH,
    MAX(a.STATUS) KEEP (DENSE_RANK FIRST ORDER BY TIME_STAMP DESC)
FROM STATUS_TABLE a
GROUP BY a.PERSON_ID, a.YEAR, a.BRANCH;

我担心的是,我发现的许多文档和示例并未将所有分组列放在 GROUP BY 中,而是为许多列编写了 KEEP 语句。

像这样:

SELECT 
    a.PERSON_ID, 
    MAX(a.YEAR) KEEP (DENSE_RANK FIRST ORDER BY TIME_STAMP DESC), 
    MAX(a.BRANCH) KEEP (DENSE_RANK FIRST ORDER BY TIME_STAMP DESC),
    MAX(a.STATUS) KEEP (DENSE_RANK FIRST ORDER BY TIME_STAMP DESC)
FROM STATUS_TABLE a
GROUP BY a.PERSON_ID;

问题
如果我知道在 TIME_STAMP 上永远不会有 ID、YEAR 和 BRANCH 的重复项,我可以用第一种方式编写它,还是仍然需要用第二种方式编写它。使用第一种方法,我得到了我期望的结果,但我似乎找不到这种方法的任何解释以及可能存在的差异。

有吗?

标签: sqloracleoracle11gaggregate-functions

解决方案


您的聚合查询是不同的。当你有:

GROUP BY a.PERSON_ID, a.YEAR, a.BRANCH

对于三列的每个组合,您的结果集中将有一行。

如果您指定:

GROUP BY a.PERSON_ID

然后每个只有一行PERSON_ID。在某些情况下,这与上述版本相同。但只有当有 oneYEARBRANCHper时PERSON_ID。在您的数据中并非如此。

对于大多数实际用途,这些版本在功能上等同于您的具有相关子查询的版本。一个区别是,如果任何分组/相关列是NULL. GROUP BY保留这些分组。相关子查询将它们过滤掉。


推荐阅读