为什么Oracle不是说GROUP BY表达式?

时间:2012-09-24 12:19:28

标签: sql oracle

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

  1. zip-code找到的所有条目都应按照邮政编码降序进行分组。
  2. 按城市找到的条目应按字母顺序进行分组。
  3. 按经销商名称找到的所有条目都应按字母顺序排序。
  4. 为了满足上述条件,我编写了如下的查询

    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表达式”

    非常感谢任何帮助

4 个答案:

答案 0 :(得分:1)

这只是因为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;
你会得到什么? 你应该得到两行,因为有两个部门,但查询要求ename。对于20是明确的但是10发动机应该返回什么?

它会返回一个错误。猜不出要给予什么。 Oracle发出错误 - 你的错误,但是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中,您不能通过查询将分析函数与group混合。

答案 1 :(得分:1)

您问题的具体答案是uuid未按表达式包含在组中。其他答案已经解释了允许这种情况发生的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,可以在两个数据库中使用。

答案 2 :(得分:0)

它适用于MySQl,因为MySQL对SQL有一种粗略的解释。

在任何正确的方言中,SELECTORDER BY子句中的任何内容都必须是聚合函数或GROUPed表达式。

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

答案 3 :(得分:0)

我不了解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;