Oracle根据最小日期之间的最小日期选择记录

时间:2015-11-18 16:40:12

标签: sql oracle aggregate-functions

我的SQL目前看起来像这样。

SELECT t1.field1,
       t1.field2,
       t1.field3,
       t1.field4,
       t1.field5,
       t1.field6,
       t1.field7,
       t1.field8,
       t2.field1,
       t2.field2,
       t2.field3,
       t2.field4,
       t2.field5,
       t2.field6,
       t2.field7,
       t2.field8,
       t2.field9,
       t3.field1,
       t4.field1,
       t5.field1,
       SUM(t6.field1),
       MIN(t6.THEDATE) 

  FROM table1 t1
    LEFT JOIN table2 t2
      ON t1.field2 = t2.sameFieldName
      LEFT JOIN table3 t3
        ON t2.field9 = t3.sameFieldName
        LEFT JOIN table4 t4
          ON t1.field2 = t4.sameFieldName
          AND t2.field1 = t4.sameFieldName
          LEFT JOIN table5 t5
            ON t4.field1 = t5.sameFieldName
            LEFT JOIN table6 t6
              ON t4.field1 = t6.sameFieldName
              AND t4.colName1 = t6.sameFieldName

  WHERE t6.THEDATE BETWEEN SYSDATE - 70 AND SYSDATE - 50
    AND t1.field2 = 'SUBMIT'
    AND t1.field3 LIKE 'H%'

  GROUP BY t1.field1,
           t1.field2,
           t1.field3,
           t1.field4,
           t1.field5,
           t1.field6,
           t1.field7,
           t1.field8,
           t2.field1,
           t2.field2,
           t2.field3,
           t2.field4,
           t2.field5,
           t2.field6,
           t2.field7,
           t2.field8,
           t2.field9,
           t3.field1,
           t4.field1,
           t5.field1;

我遇到的问题是我需要根据最小日期选择条件。但这样做会显示"显示"最小日期,但它会根据最后一个" theDate"来过滤记录。价值是。我知道你不能在where子句中使用agg函数,因为where只对单个记录进行操作。那么我怎样才能得到像这样的东西呢?

SELECT *, sum(somthing), min(theDate)
FROM Table
WHERE min(theDate) BETWEEN SYSDATE - 70 AND SYSDATE - 50
GROUP BY <<<ALL GROUP COLUMNS>>>

4 个答案:

答案 0 :(得分:2)

您发布的语法无效 - 您不能group by *,因为您要选择其他列,所以您需要在select *上添加别名。假设这些只是组合简化示例的工件,您只需要使用having子句

SELECT a.*, sum(something), min(theDate)
  FROM table_name a
 GROUP BY <<list of columns in a>>
HAVING min(theDate) BETWEEN sysdate - 70 AND sysdate - 50

答案 1 :(得分:1)

根据数据的大小,在进行聚合之前过滤记录可能是最快的。适当的过滤器是:

tagsInputConfig.setDefaults('tagsInput', {
    placeholder: 'Search',
    maxTags: 10,
    minLength: 5,
    maxLength: 40,
    replaceSpacesWithDashes: false,
    onTagAdding: function (x,y,z) {
        debugger; // breakpoint is never called
    }
});

<tags-input on-tag-adding="onTagAdding($tag)" ng-model="search"></tags-input> 是基于使用SELECT *, sum(somthing), min(theDate) FROM Table t WHERE NOT EXISTS (SELECT 1 FROM table t2 WHERE . . . AND t2.thedate < SYSDATE - 70) AND EXISTS (SELECT 1 FROM table t2 WHERE . . . AND t2.thedate <= sysdate - 50) GROUP BY * 注释的组的平等条件。

答案 2 :(得分:0)

您可以使用分析函数:

SELECT * FROM
(
SELECT *, sum(somthing) over(), row_number() over (order by theDate) as rn
FROM Table
WHERE theDate BETWEEN SYSDATE - 70 AND SYSDATE - 50
)
WHERE rn = 1;

您可以使用rank()而不是row_number(),但如果在最多1行中使用最小日期值,则可能返回多于1行。

答案 3 :(得分:0)

GROUP BY中的主要性能消耗可能是不必要的列。如果您的Table引用非规范化表格,则会发生这种情况:

EMP (EMP_ID*, DEPT_ID, DEPT_NAME, SAL, THEDATE)

Table是否指加号,例如

EMP(EMP_ID*, DEPT_ID, SAL, THEDATE)
DEPT(DEPT_ID*, DEPT_NAME)

"Table" == EMP JOIN DEPT USING (DEPT_ID)

在任何一种情况下,查询:

SELECT DEPT_ID, DEPT_NAME, SUM(SAL), MIN(THEDATE)
FROM   EMP
GROUP BY DEPT_ID, DEPT_NAME
HAVING MIN(THEDATE) >= SYSDATE-70 AND MIN(THEDATE) < SYSDATE-50;

将会遇到对DEPT_NAME进行分组的所有开销,即使DEPT_NAME对于给定的DEPT_ID始终具有相同的值。换句话说,DEPT_ID是所选列的候选键。如果SELECT *, SUM(whatever)中的“*”有一个或多个候选键(通常是所有“_ID”列)确定所有其他列的唯一值,那么执行以下操作会更有效:

SELECT DEPT_ID, MAX(DEPT_NAME) DEPT_NAME, SUM(SAL), MIN(THEDATE)
FROM   EMP USING (DEPT_ID)
GROUP BY DEPT_ID
HAVING MIN(THEDATE) >= SYSDATE-70 AND MIN(THEDATE) < SYSDATE-50;

如果您的从属列是长字符串,性能差异可能会特别显着。

Gordon Linoff的回答很有意义(虽然我认为他的实现可以进一步优化,见下文) - 在某些情况下,“预过滤”是有意义的。很少有经验法则表明这可能会更快:
1)大多数(80%以上)的行具有超过70天的THEDATE
2)Table上的单个索引,其中包含大多数/所有GROUP BY列,最好是THEDATE个 3)THEDATE上的单独索引或THEDATE是#2中注明的索引的第一列 4)或者#3 - TableTHEDATE分区(#2中的索引是本地索引会更好)

基本的“预过滤逻辑”:对所有Table行求和 1)不属于任何行“太旧”的分组
2)属于至少有一行“足够老但不太老”的分组 3)行本身并不“太旧”

SELECT  DEPT_ID, DEPT_NAME, SUM(SAL), MIN(THEDATE)
FROM    EMP E1
WHERE   NOT EXISTS 
            (SELECT 1 FROM EMP E2 
             WHERE E2.DEPT_ID = E1.DEPT_ID 
                   AND E2.DEPT_NAME=E1.DEPT_NAME
                   AND E2.THEDATE < SYSDATE - 70)
        AND EXISTS
            (SELECT 1 FROM EMP E2 
             WHERE E2.DEPT_ID = E1.DEPT_ID 
                   AND E2.DEPT_NAME=E1.DEPT_NAME
                   AND E2.THEDATE BETWEEN SYSDATE-70 AND SYSDATE - 50)
       AND E1.THEDATE >= SYSDATE -70
GROUP BY DEPT_ID, DEPT_NAME;

最后注意事项:如果候选键分组和预过滤器优化似乎都适用,它们可以串联应用:

SELECT  DEPT_ID, MAX(DEPT_NAME) DEPT_NAME, SUM(SAL), MIN(THEDATE)
FROM    EMP E1
WHERE   NOT EXISTS 
            (SELECT 1 FROM EMP E2 
             WHERE E2.DEPT_ID = E1.DEPT_ID 
                   AND E2.THEDATE < SYSDATE - 70)
        AND EXISTS
            (SELECT 1 FROM EMP E2 
             WHERE E2.DEPT_ID = E1.DEPT_ID 
                   AND E2.THEDATE BETWEEN SYSDATE-70 AND SYSDATE - 50)
       AND E1.THEDATE >= SYSDATE -70
GROUP BY DEPT_ID;

除此之外,你可以做更多的事情来提高查询的性能(尽管PARALLELISM可能是一个选项)。要更快地获得正确的结果,您必须查看结构更改(席子视图,索引,分区选项等)以支持查询。