【问题标题】:Encountering ORA-00979: not a GROUP BY expression when using CASE - IN statements in sql遇到 ORA-00979: not a GROUP BY expression when using CASE - IN statements in sql
【发布时间】:2011-04-18 16:42:09
【问题描述】:

这行得通:

 SELECT (CASE
             WHEN x = 'value' THEN
              a.col1
             ELSE
              nvl(a.col1, a.col2)
           END)
      FROM table1 a
     WHERE a.this = 'that'
     GROUP BY (CASE
                WHEN x = 'value'  THEN
                 a.col1
                ELSE
                 nvl(a.col1, a.col2)
              END)

但是尝试让 case 语句执行 IN 语句(在此处尝试更动态的 sql),以下代码会导致 ORA-00979 错误。

SELECT (CASE
         WHEN x IN (SELECT me FROM here WHERE this = 'example') THEN
          a.col1
         ELSE
          nvl(a.col1, a.col2)
       END)
  FROM table1 a
 WHERE a.this = 'that'
 GROUP BY (CASE
            WHEN x IN (SELECT me FROM here WHERE this = 'example') THEN
             a.col1
            ELSE
             nvl(a.col1, a.col2)
          END)

是否有可能使这项工作或有替代方案?谢谢。 --乔纳斯

Benoit:这是根据您的 sql 重新创建错误的修改后的 sql:

select (case when a.y IN (select 'A'||ROWNUM from dual where rownum=1) then 1 else 0 end)
from (SELECT 'A'||ROWNUM y, 'B' x FROM DUAL CONNECT BY ROWNUM <= 3) a where x = 'B'
group by (case when a.y IN (select 'A'||ROWNUM from dual where rownum=1) then 1 else 0 end)
;

基本上缺少的是 FROM 表应该有多个值,并且在 CASE 语句中引用了一个列。

【问题讨论】:

  • 您使用的是什么版本的 Oracle?
  • 忘记添加了。我们正在使用 Oracle 10g
  • 您最后的选择适用于 Oracle 11gR2,而不是 v9。
  • 感谢 Benoit,确认它在 11g 中有效。不幸的是,我们被困在 10g 上,我希望找到解决方法。

标签: sql oracle plsql ora-00979


【解决方案1】:

我无法通过以下请求重现此错误(工作):

select (case when 'X' IN (select dummy from dual where rownum=1) then 1 else 0 end)
from dual
where dummy = 'X'
group by (case when 'X' IN (select dummy from dual where rownum=1) then 1 else 0 end)
;

试试:

WITH table1_extended AS (
   SELECT a.*, CASE WHEN x IN .... END "condition"
     FROM table1 a
)
SELECT b."condition"
  FROM table1_extended b
 WHERE b.this = 'that'
 GROUP BY b."condition"

【讨论】:

  • 有趣。确实,虚拟测试有效。我将更多地研究我的选择并尝试使用更准确的虚拟 sql。我的好先生,现在为你投票。
  • 我忘了说我已经在 11g 版本 11.2.0.1.0 64 位以及 9.2.0.6.0 上测试过它。
  • Benoit,我进行了编辑,应该可以复制我所看到的内容。谢谢,
  • WITH 语法没有帮助吗?
  • 做了很多工作,但是是的。这是解决方案的一个很好的起点。谢谢!
【解决方案2】:

是否有不能将子选择移动到连接中的原因?从@Benoit 测试用例的调整版本中,您可以这样做:

select case when a.y = b.z then 1 else 0 end, count(*)
from (select 'A'||rownum y, 'B' x from dual connect by rownum <= 3) a,
    (select 'A'||rownum z from dual where rownum=1) b
where a.x = 'B'
group by case when a.y = b.z then 1 else 0 end;

提供(10g):

CASEWHENA.Y=B.ZTHEN1ELSE0END COUNT(*)               
---------------------------- ---------------------- 
1                            1                      
0                            2

不完全相信它会给出你想要的答案,但很难说,因为它是如此简化,并且可能是一个起点。


编辑 看来这确实太简单了。另一种可能的解决方案看起来也太简单但可能会奏效,那就是从另一端处理这个问题,并将select 中的case 设为聚合函数:
SELECT MIN(CASE
         WHEN x IN (SELECT me FROM here WHERE this = 'example') THEN
          a.col1
         ELSE
          nvl(a.col1, a.col2)
       END)
  FROM table1 a
 WHERE a.this = 'that'
 GROUP BY (CASE
            WHEN x IN (SELECT me FROM here WHERE this = 'example') THEN
             a.col1
            ELSE
             nvl(a.col1, a.col2)
          END)

【讨论】:

  • 你的代码作为上下文,'b'应该是一个配置表,所以如果我们将子选择移动到连接中,我们将得到一个笛卡尔。是的,实际的代码是复杂的业务逻辑。
  • @jonasespelita:笛卡尔连接本质上并不坏。如果您的第二个选择始终返回一行,则笛卡尔结果不会比您编写的查询的结果大,并且性能应该几乎相同。
  • @Allan 确实。但是由于在实际生产中,第二次选择返回十几行..你明白了。 :) 感谢您的信息。
猜你喜欢
  • 2013-03-10
  • 1970-01-01
  • 2021-10-26
  • 2012-11-16
  • 1970-01-01
  • 2011-10-25
  • 2022-01-22
  • 2021-09-12
  • 1970-01-01
相关资源
最近更新 更多