【问题标题】:Why Oracle is saying not a GROUP BY expression?为什么 Oracle 说不是 GROUP BY 表达式?
【发布时间】:2012-09-15 21:44:50
【问题描述】:

我正在尝试使用以下条件从 Oracle 数据库表中检索数据

  1. 按邮政编码找到的所有条目都应分组,按邮政编码降序排序。
  2. 按城市找到的条目应按字母顺序分组。
  3. 按经销商名称找到的所有条目都应按字母顺序分组和排序。

为了满足上述条件,我编写了如下查询

SELECT DISTINCT ba.uuid AS uuid
        , COUNT(*) over() AS rowcount 
FROM basicaddress ba 
WHERE ba.postalcode='143456' 
OR ba.lastname LIKE '%143456%' 
OR ba.city LIKE '%143456%'
GROUP BY
    CASE WHEN ba.postalcode='143456' THEN ba.postalcode END 
ORDER BY 
    CASE WHEN ba.postalcode='143456' THEN ba.postalcode END DESC, 
    CASE WHEN ba.lastname LIKE '%143456%' THEN ba.lastname END ASC, 
    CASE WHEN ba.city LIKE '%143456%' THEN ba.city ELSE ba.postalcode END DESC

此查询在 MYSQL 中运行良好,但在 oracle 中它说 “不是 GROUP BY 表达式”

任何帮助将不胜感激

【问题讨论】:

  • 不,这在任何 SQL 方言中都会出错。
  • @ypercube select ename, dept from emp group by dept 在 MySql 中工作,只是 ename 不保证相同。它是从组中选择的。我同意这是一个误导性的错误来源,尤其是对于初学者。
  • @Florin:我不是指那个。请参阅问题的第一版。 CASE 表达式无效。

标签: sql oracle


【解决方案1】:

我不了解 MySQL,但以下适用于 Oracle 11g:

With 
T_PATTERN as (select '%143456%' as PATTERN from DUAL)
, T_INPUT as (
  select 1 as UUID, 'X143456y' as FIRSTNAME, 'last1' as LASTNAME, 'u143456v' as CITY, 'w143456z' as POSTALCODE from DUAL union
  select 2 as UUID, 'first2' as FIRSTNAME, 'a143456b' as LASTNAME, 'a143456b' as CITY, 'postal2' as POSTALCODE from DUAL union
  select 3 as UUID, 'first3' as FIRSTNAME, 'last3' as LASTNAME, 'c143456d' as CITY, 'postal3' as POSTALCODE from DUAL union
  select 4 as UUID, 'first4' as FIRSTNAME, 'last4' as LASTNAME, 'city4' as CITY, 'postal4' as POSTALCODE from DUAL
),
Q_FNAME as (
  select TI.UUID, TI.FIRSTNAME, COUNT(*) FN_COUNT from T_INPUT TI inner join T_PATTERN TP on 1=1 
  where UPPER(TI.FIRSTNAME) like TP.PATTERN
  GROUP BY TI.UUID, TI.FIRSTNAME
),
Q_LNAME as (
  select TI.UUID, TI.LASTNAME, COUNT(*) LN_COUNT from T_INPUT TI inner join T_PATTERN TP on 1=1 
  where UPPER(TI.LASTNAME) like TP.PATTERN
  group by TI.UUID, TI.LASTNAME
),
Q_CITY as (
  select TI.UUID, TI.CITY, COUNT(*) CT_COUNT from T_INPUT TI inner join T_PATTERN TP on 1=1 
  where UPPER(TI.CITY) like TP.PATTERN
  group by TI.UUID, TI.CITY
),
Q_PCODE as (
  select TI.UUID, TI.POSTALCODE, COUNT(*) PC_COUNT from T_INPUT TI inner join T_PATTERN TP on 1=1 
  where UPPER(TI.POSTALCODE) like TP.PATTERN
  group by TI.UUID, TI.POSTALCODE
)
select TI.UUID, TI.FIRSTNAME, TI.LASTNAME, TI.CITY, TI.POSTALCODE, 
  QF.FN_COUNT, QL.LN_COUNT, QC.CT_COUNT, QP.PC_COUNT
from T_INPUT ti
left join Q_FNAME QF on TI.UUID=QF.UUID
left join Q_LNAME QL on TI.UUID=QL.UUID
left join Q_CITY QC on TI.UUID=QC.UUID
left join Q_PCODE QP on TI.UUID=QP.UUID
order by ti.UUID;

【讨论】:

    【解决方案2】:

    您的问题的具体答案是 uuid 不包含在 group by 表达式中。其他答案已经解释了允许这种情况发生的 MySQL (mis) 功能。修复查询很容易:

    SELECT ba.uuid AS uuid, COUNT(*) over() AS rowcount
    FROM basicaddress ba 
    WHERE ba.postalcode='143456' OR ba.lastname LIKE '%143456%' OR ba.city LIKE '%143456%'
    GROUP BY uuid,
            CASE WHEN ba.postalcode='143456' THEN ba.postalcode END 
    ORDER BY 
            max(CASE WHEN ba.postalcode='143456' THEN ba.postalcode END) DESC, 
            max(CASE WHEN ba.lastname LIKE '%143456%' THEN ba.lastname END) ASC, 
            max(CASE WHEN ba.city LIKE '%143456%' THEN ba.city ELSE ba.postalcode END)
    

    我还删除了在使用 group by 时应该是多余的“distinct”。

    也就是说,我不明白这如何满足您最初的问题。我期待更多类似以下内容:

    select (case when postalcode is not null then postalcode
                 when city is not null then city
                 when lastname is not null then lastname
            end),
           (case when postalcode is not null then 1
                 when city is not null then 2
                 when lastname is not null then 3
            end),
           count(*)
    from basicaddress ba
    group by (case when postalcode is not null then postalcode
                   when city is not null then city
                   when lastname is not null then lastname
              end),
             (case when postalcode is not null then 1
                 when city is not null then 2
                 when lastname is not null then 3
            end)
    order by 1, 2
    

    这可能不是您所需要的,但它应该为您指明正确的方向。此外,这是标准 SQL,适用于两个数据库。

    【讨论】:

      【解决方案3】:

      这发生在你身上只是因为 MySQL 破坏了 SQL 的逻辑。

      假设我们有表 emp:

      id ename dept
      1  mark  10
      2  John  10
      3  Mary  10
      4  Jane  20
      

      和查询:

      select dept, ename
      from emp 
      group by dept;
      

      你会得到什么? 你应该得到两行,因为有两个部门,但查询要求输入姓名。对于 20 是明确的,但对于 10,引擎应该返回什么?

      它应该返回一个错误。猜不出要给什么名字。 甲骨文报错 - 你的错误,但 MySQL 得到一个 ename(不保证哪个)。 这是误导性的,可能会产生错误。

      正确的查询是:

      select dept, max(ename) --the latest, alaphabeticaly
      from emp 
      group by dept;
      

      --all enames and groups
      select dept, ename 
      from emp 
      group by dept, ename;
      

      纠正这部分后,您必须解决

      COUNT(*) over() AS rowcount
      

      部分。在 oracle、AFAIK 中,您不能将分析函数与分组查询混合使用。

      【讨论】:

        【解决方案4】:

        它在 MySQl 中有效,因为 MySQL 对 SQL 的解释很拙劣。

        在任何适当的方言中,SELECTORDER BY 子句中的任何内容都需要是聚合函数或 GROUPed 表达式。

        至少,您需要按 ba.uuid、姓氏和城市进行分组。

        【讨论】:

          猜你喜欢
          • 2017-09-21
          • 2011-08-14
          • 2011-06-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-30
          • 1970-01-01
          • 2014-12-28
          相关资源
          最近更新 更多