关于sql:Oracle throws Not a group by expression

Oracle throws Not a group by expression

我有一个查询,我使用一个右连接日期表的表,这意味着我得到所有日期值。我只想让我的表格结果集的边界之间的值。我有以下查询

1
2
3
4
5
6
SELECT DD.CAL_YEAR, DD.WEEK_OF_YEAR, COUNT(DISTINCT FPP.ID) AS Total
FROM FACT_PAY_PAYMENT FPP
    RIGHT JOIN DIM_DATE DD ON FPP.REQUESTED_EXECUTION_DATE_ID = DD.ID
GROUP BY DD.CAL_YEAR, DD.WEEK_OF_YEAR
HAVING DD.ID >= MIN(FPP.REQUESTED_EXECUTION_DATE_ID)
   AND DD.ID <= MAX(FPP.REQUESTED_EXECUTION_DATE_ID);

但是当我执行此操作时,我从 Oracle

收到以下错误

Error: ORA-00979: not a GROUP BY expression

SQLState: 42000 ErrorCode: 979

我的查询有什么问题?


在您的查询中,问题是最后一条语句 (having):

1
2
3
4
5
SELECT DD.CAL_YEAR, DD.WEEK_OF_YEAR, COUNT(DISTINCT FPP.ID) AS Total
    FROM FACT_PAY_PAYMENT FPP
    RIGHT JOIN DIM_DATE DD ON FPP.REQUESTED_EXECUTION_DATE_ID = DD.ID
    GROUP BY DD.CAL_YEAR,DD.WEEK_OF_YEAR
--->        Having DD.ID >= MIN(FPP.REQUESTED_EXECUTION_DATE_ID) AND DD.ID <= MAX(FPP.REQUESTED_EXECUTION_DATE_ID)

确实,have 也应该应用于 group by 中包含的字段,而 DD.ID 则不是这样。
所以甲骨文抱怨(现在更清楚)消息"(DD.ID是)not(in)a group by expression"

如果与您的业务逻辑兼容,可能的解决方案是将您的 having 子句转换为简单的 where 子句:

1
2
3
4
5
6
SELECT DD.CAL_YEAR, DD.WEEK_OF_YEAR, COUNT(DISTINCT FPP.ID) AS Total
    FROM FACT_PAY_PAYMENT FPP
    RIGHT JOIN DIM_DATE DD ON FPP.REQUESTED_EXECUTION_DATE_ID = DD.ID
    WHERE DD.ID >= ...
    AND DD.ID <= ...
    GROUP BY DD.CAL_YEAR,DD.WEEK_OF_YEAR

在这里你可以找到对 having vs where 子句的很好的解释。


您似乎想要最小值和最大值之间的所有日期值,即使是那些没有匹配值的日期值。我猜每年和每周的聚合只会从 DD 获得少数 id。所以,一种方法是:

1
2
3
4
5
6
7
SELECT DD.CAL_YEAR, DD.WEEK_OF_YEAR, COUNT(DISTINCT FPP.ID) AS Total
FROM DIM_DATE DD LEFT JOIN
     FACT_PAY_PAYMENT FPP
     ON FPP.REQUESTED_EXECUTION_DATE_ID = DD.ID
GROUP BY DD.CAL_YEAR, DD.WEEK_OF_YEAR
HAVING MAX(DD.ID) >= MIN(FPP.REQUESTED_EXECUTION_DATE_ID) AND
       MIN(DD.ID) <= MAX(FPP.REQUESTED_EXECUTION_DATE_ID);

但是,在 having 子句中执行此过滤是浪费精力——查询已经聚合了所有内容。这是一种在 where:

中获取它的方法

1
2
3
4
5
6
7
8
9
10
SELECT DD.CAL_YEAR, DD.WEEK_OF_YEAR, COUNT(DISTINCT FPP.ID) AS Total
FROM DIM_DATE DD LEFT JOIN
     FACT_PAY_PAYMENT FPP
     ON FPP.REQUESTED_EXECUTION_DATE_ID = DD.ID CROSS JOIN
     (SELECT MIN(FPP.REQUESTED_EXECUTION_DATE_ID) AS minredi,
             MAX(FPP.REQUESTED_EXECUTION_DATE_ID) AS maxredi
      FROM FACT_PAY_PAYMENT
     ) minmax
WHERE DD.ID >= minmax.minredi AND DD.ID <= minmax.maxredi
GROUP BY DD.CAL_YEAR, DD.WEEK_OF_YEAR;