【问题标题】:Aggregate in case statement with "not a GROUP BY expression" error在 case 语句中聚合“不是 GROUP BY 表达式”错误
【发布时间】:2020-11-12 19:53:31
【问题描述】:

为什么当我在查询中包含以下 case 语句时,即使下面的 case 语句使用了 GROUP BY 中不允许的聚合,我也会收到“不是 GROUP BY 表达式”错误? 当我在 GROUP BY 中包含 case 语句时,当然会出现“此处不允许使用组函数”错误,但是当我从 GROUP BY 中删除它时,我会再次出现“不是 GROUP BY 表达式”错误。

谁能解释一下?提前谢谢!

        ,case
                when
                        round(sum(i.INVOICE_AMOUNT))  > 50000 and 
                        (cont_all.CONTRACT_EFFECTIVE_DATE > '&end_date'
                        or cont_all.CONTRACT_EXPIRATION_DATE <= '&end_date'
                        or cont_all.CONTRACT_EFFECTIVE_DATE is null) 
                        then 'Over 50k and no Contract'
                else 'Contract or No Contract with spend below 50k'
                end as "Contract Needed?"

这是 mathguy 建议的完整查询:

define end_date = '30-SEP-20'

    select
             v.SEGMENT1 "Vendor Number"
            ,v.VENDOR_NAME "Vendor Name"
            ,s.VENDOR_SITE_CODE "Site Name"
            ,case
                    when s.ORG_ID in ('285',    '296',  '294',  '327',  '304',  '297',  '295',  '312',  '313',  '315',  '319',  '322',  '321',  '306') then 'Fleet'
                    else 'Non-Fleet'
                    end as "Fleet / Non-Fleet"
            ,case
                    when s.ORG_ID in ('288','325','285') then 'Belgium'
                    when s.ORG_ID in ('301','296','302','294') then 'Germany'
                    when s.ORG_ID in ('327','305','304') then 'Spain'
                    when s.ORG_ID in ('298','303','297','299','300','295') then 'France'
                    when s.ORG_ID in ('309','307') then 'Ireland'
                    when s.ORG_ID in ('316','312','314','317','313') then 'Italy'
                    when s.ORG_ID in ('318','315') then 'Luxembourg'
                    when s.ORG_ID in ('318','315') then 'Monaco'
                    when s.ORG_ID in ('322','323','324','326','321') then 'Netherlands'
                    when s.ORG_ID in ('308','310','311','306') then 'United Kingdom'
                    else 'Error'
                    end as "Country"
            ,o.NAME "Operating Unit"
            ,to_number(round(sum(i.INVOICE_AMOUNT))) "Spend last 12 months"
            ,case
                    when round(sum(i.INVOICE_AMOUNT))  > 50000 then 'Over 50,000'
                    when round(sum(i.INVOICE_AMOUNT))  <= 50000 then 'Below 50,000'
                    when round(sum(i.INVOICE_AMOUNT))  = 0 then 'No spend'
                    when round(sum(i.INVOICE_AMOUNT))  is null then 'No spend'
                    else 'Wrong'
                    end as "Spend brackets last 12 months"
            ,case
                    when cont_all.CONTRACT_EFFECTIVE_DATE <='&end_date' then 'Contract'
                    when cont_all.CONTRACT_EFFECTIVE_DATE > '&end_date' then 'No Contract'
                    when cont_all.CONTRACT_EXPIRATION_DATE <= '&end_date' then 'No Contract'
                    when cont_all.CONTRACT_EXPIRATION_DATE > '&end_date' then 'Contract'
                    when cont_all.CONTRACT_EFFECTIVE_DATE is null then 'No Contract'
                    else 'Wrong'
                    end as "Contract Indicator"
--            ,case
--                    when
--                            round(sum(i.INVOICE_AMOUNT))  > 50000 and 
--                            (cont_all.CONTRACT_EFFECTIVE_DATE > '&end_date'
--                            or cont_all.CONTRACT_EXPIRATION_DATE <= '&end_date'
--                            or cont_all.CONTRACT_EFFECTIVE_DATE is null) 
--                            then 'Over 50k and no Contract'
--                    else 'Contract or No Contract with spend below 50k'
--                    end as "Contract Needed?"
            ,t.NAME "Terms"
            ,TO_CHAR(TO_DATE('&end_date', 'DD-MON-YYYY'), 'Mon YY') Month
            
from
            AP.AP_SUPPLIERS v
            join AP.AP_SUPPLIER_SITES_ALL s on v.VENDOR_ID=s.VENDOR_ID
            join apps.HR_ALL_ORGANIZATION_UNITS o on s.ORG_ID=o.ORGANIZATION_ID 
            left join AP.AP_INVOICES_ALL i on s.VENDOR_SITE_ID=i.VENDOR_SITE_ID
            left join AP_TERMS_TL t on s.TERMS_ID=t.TERM_ID
            left join APPS.OKC_REP_CONTRACT_PARTIES cont on v.VENDOR_ID=cont.PARTY_ID
            left join APPS.OKC_REP_CONTRACTS_ALL cont_all on cont.CONTRACT_ID=cont_all.CONTRACT_ID

where
            ((v.end_date_active is null or v.end_date_active > '&end_date') and (s.inactive_date is null or s.inactive_date > '&end_date'))
            and v.CREATION_DATE <= '&end_date'
            and s.ORG_ID in  ('324','288','325','285','301','296','302','294','327','305','304','298','303','297','299','300','295','309','307','316','312','314','317','313','318','315','320','319','322','323','326','321','308','310','311','306')
            and v.SEGMENT1 = 259456
            and i.CREATION_DATE between add_months('&end_date', -12) and '&end_date'
            and i.CANCELLED_DATE is null
                  
group by
            v.SEGMENT1
            ,v.VENDOR_NAME
            ,s.VENDOR_SITE_CODE
            ,case
                    when s.ORG_ID in ('285',    '296',  '294',  '327',  '304',  '297',  '295',  '312',  '313',  '315',  '319',  '322',  '321',  '306') then 'Fleet'
                    else 'Non-Fleet'
                    end
            ,case
                    when s.ORG_ID in ('288','325','285') then 'Belgium'
                    when s.ORG_ID in ('301','296','302','294') then 'Germany'
                    when s.ORG_ID in ('327','305','304') then 'Spain'
                    when s.ORG_ID in ('298','303','297','299','300','295') then 'France'
                    when s.ORG_ID in ('309','307') then 'Ireland'
                    when s.ORG_ID in ('316','312','314','317','313') then 'Italy'
                    when s.ORG_ID in ('318','315') then 'Luxembourg'
                    when s.ORG_ID in ('318','315') then 'Monaco'
                    when s.ORG_ID in ('322','323','324','326','321') then 'Netherlands'
                    when s.ORG_ID in ('308','310','311','306') then 'United Kingdom'
                    else 'Error'
                    end
            ,o.NAME
            ,case
                    when cont_all.CONTRACT_EFFECTIVE_DATE <='&end_date' then 'Contract'
                    when cont_all.CONTRACT_EFFECTIVE_DATE > '&end_date' then 'No Contract'
                    when cont_all.CONTRACT_EXPIRATION_DATE <= '&end_date' then 'No Contract'
                    when cont_all.CONTRACT_EXPIRATION_DATE > '&end_date' then 'Contract'
                    when cont_all.CONTRACT_EFFECTIVE_DATE is null then 'No Contract'
                    else 'Wrong'
                    end
--            ,case
--                    when
--                            (round(sum(i.INVOICE_AMOUNT))  > 50000
--                            and 
--                            (cont_all.CONTRACT_EFFECTIVE_DATE > '&end_date'
--                            or cont_all.CONTRACT_EXPIRATION_DATE <= '&end_date'
--                            or cont_all.CONTRACT_EFFECTIVE_DATE is null) )
--                            then 'Over 50k and no Contract'
--                    else 'Contract or No Contract with spend below 50k'
--                    end
            ,t.NAME
            ,TO_CHAR(TO_DATE('&end_date', 'DD-MON-YYYY'), 'Mon YY')

【问题讨论】:

  • 这有点难以分辨,没有看到你的分组依据。例如:如果您没有在 GROUP BY 中包含 CONTRACT_EFFECTIVE_DATE,为什么您认为您的表达式应该被认为是有效的?对于同一组中的不同行,应该使用哪个(可能不同的)生效日期进行比较?
  • 同意@mathguy;我们需要查看 GROUP BY 和 ORDER BY 才能更好地理解。如果 CONTRACT_EFFECTIVE_DATE 和 CONTRACT_EXPIRATION_DATE 不是 GROUP BY 的一部分,则会引发错误,但我们只能在没有更多查询的情况下进行猜测。
  • @mathguy 和 CoffeeNeedCoffee,谢谢。我在我的问题中包含了完整的查询。
  • 不相关,但永远无法到达'No spend',因为它首先落在&lt;= 50000 括号中(除非null

标签: sql oracle aggregates


【解决方案1】:

这是您的简化示例

create table  tab as
select 
1 SEGMENT1,
sysdate + rownum as CONTRACT_EFFECTIVE_DATE, rownum INVOICE_AMOUNT from dual 
connect by level <= 10;

select 
  SEGMENT1,
  case when sum(INVOICE_AMOUNT) > 50 and CONTRACT_EFFECTIVE_DATE > DATE'2020-01-01' then 'OK' else 'NOK' end as col1
from tab  
group by SEGMENT1;

这当然会导致ORA-00979: not a GROUP BY expression,因为你 group by CONTRACT_EFFECTIVE_DATE

但添加 CONTRACT_EFFECTIVE_DATE 很可能不是您想要的。

我猜你需要将过滤条件放入聚合函数,像这样 - 所以你聚合INVOICE_AMOUNT 仅当条件已满并将结果与​​阈值进行比较 p>

select 
  SEGMENT1,
  case when 
      sum(case when CONTRACT_EFFECTIVE_DATE > DATE'2020-01-01'then INVOICE_AMOUNT end) > 50  
  then 'OK' else 'NOK' end as col1
from tab  
group by SEGMENT1;

【讨论】:

  • 非常感谢。是的,你是对的,我不想在 CONTRACT_EFFECTIVE_DATE 进行 GROUP BY,你的解决方案看起来很棒!
  • @Adrian 你很高兴,当然你可以额外投票和/或接受答案。
  • 道歉。我对这个论坛不是很有经验。赞成并接受。再次感谢您!
猜你喜欢
  • 1970-01-01
  • 2019-10-23
  • 2017-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 2013-11-19
  • 1970-01-01
相关资源
最近更新 更多