在非聚合中使用聚合结果导致 GROUP BY 出现问题

Posted

技术标签:

【中文标题】在非聚合中使用聚合结果导致 GROUP BY 出现问题【英文标题】:Using result from aggregate in non aggregate causing issues with GROUP BY 【发布时间】:2017-03-16 04:17:28 【问题描述】:

我的查询中有一个列导致我的 group by 出现问题。如果我在组中包含该列,则会收到错误消息:“GROUP BY 和 WITH...BY 子句可能不包含聚合函数。”但是如果我从 GROUP 中删除该列,我会得到“选定的非聚合值必须是关联组的一部分。”

我认为问题在于,虽然该列没有自行聚合,但它使用的是聚合列。如果我在那个问题上是正确的,请告诉我,和/或我该如何解决。

SELECT
        //r.publicid as nNumber, 
        u.publicid as nNumber,
        d.name as department, concat(c.lastname,', ',c.firstname) AS fullName, SUBSTRING(cc2.name,1,4) as Office,
        u.jobtitle as jobTitle, 
        CASE WHEN LENGTH(cxm.lm_extension) = 5.0 THEN concat('72',cxm.lm_extension) ELSE cxm.lm_extension END AS formattedExtension,    

        //Checks how many regions are associated to user. Concatenates multiple regions      
        MAX(CASE WHEN rn = '1' THEN r.regionName END)
        || MAX(CASE WHEN rn = 2 THEN ',' || r.regionName ELSE '' END)
        || MAX(CASE WHEN rn = 3 THEN ',' || r.regionName ELSE '' END)
        || MAX(CASE WHEN rn = 4 THEN ',' || r.regionName ELSE '' END)
        || MAX(CASE WHEN rn = 5 THEN ',' || r.regionName ELSE '' END) AS region,        

        s.segmentationAttribute,       

        //Checks LOB, Department, Region and Segmentation attribute to determine the appropriate Zero out     
        CASE                 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Third Party PD - High Complexity' AND region = 'Northeast') THEN 'C_APD_NE_HC3_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - First Party PD - High Complexity' AND region = 'Northeast') THEN 'C_APD_NE_HC1_COV' 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Low Complexity' AND region = 'Northeast') THEN 'C_APD_NE_LC_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Third Party PD - High Complexity' AND region = 'Mid-Atlantic') THEN 'C_APD_MA_HC3_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - First Party PD - High Complexity' AND region = 'Mid-Atlantic') THEN 'C_APD_MA_HC1_COV' 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Low Complexity' AND region = 'Mid-Atlantic') THEN 'C_APD_MA_LC_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Third Party PD - High Complexity' AND region = 'Central') THEN 'C_APD_C_HC3_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - First Party PD - High Complexity' AND region = 'Central') THEN 'C_APD_C_HC1_COV' 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Low Complexity' AND region = 'Central') THEN 'C_APD_C_LC_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Third Party PD - High Complexity' AND region = 'Southeast') THEN 'C_APD_SE_HC3_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - First Party PD - High Complexity' AND region = 'Southeast') THEN 'C_APD_SE_HC1_COV' 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Low Complexity' AND region = 'Southeast') THEN 'C_APD_SE_LC_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Third Party PD - High Complexity' AND region = 'West') THEN 'C_APD_W_HC3_COV'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - First Party PD - High Complexity' AND region = 'West') THEN 'C_APD_W_HC1_COV' 
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'APD - Low Complexity' AND region = 'West') THEN 'C_APD_W_LC_COV'
        //Block below checks for appraisal and region
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0275') THEN 'C0275 Sk324Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0336') THEN 'C0336 Sk466 Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0980') THEN 'C0980 Sk554Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0508') THEN 'C0508 Sk680 Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0897') THEN 'C0897 Sk1052Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0647') THEN 'C0647 Sk829 Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0631') THEN 'C0631 Sk795 Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0414') THEN 'C0414_Sk594_Cov_0Out'
        WHEN (department LIKE '%APD%' AND department LIKE '%Appraiser%' AND office = '0179') THEN 'C0179_SK100Cov_0Out'
        WHEN (department LIKE '%APD%' AND segmentationAttribute = 'No segmentation attribute assigned') THEN 'No segmentation attribute assigned'
        WHEN (department LIKE '%APD%' AND region LIKE '%,%') THEN 'Multiple Regions assigned'           
        //Checks for Property water mit
        WHEN (department LIKE '%PROP%' AND department LIKE '%WATER MITIGATION%') THEN 'C0980_Sk1107_0Out'         
        //Checks property and region
        WHEN (department LIKE '%PROP%' AND office = '0150') THEN 'C0150_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND (office = '0980' OR office = '0900')) THEN 'C0980_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND (office = '0508' OR office = '0520')) THEN 'C0508_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND office = '0203') THEN 'C0203_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND (office = '0631' OR office = '0633')) THEN 'C0631_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND office = '0414') THEN 'C0414_Prop0_Out'
        WHEN (department LIKE '%PROP%' AND office = '0467') THEN 'C0467_0_Out_Sk1249'
        //Checks for NF. NF zero outs are organized by teams, no data point to query on
        WHEN (department LIKE '%NF%' OR department LIKE '%NO FAULT%') THEN 'NF'
        //Safeco Zero outs have not been determined
        WHEN department LIKE '%Saf%' THEN 'Safeco, need updated Zero outs.'
        //BI users should not have zero outs      
        WHEN department LIKE '%BI%' THEN 'No Zero Out'
        //Catch all for users not fitting into previous categories            
        ELSE 'Does not fit in any category.' 
        END AS expectedZeroOut               
FROM               
        pm_ods_cl_cc_prl_d.cc_user AS u
        JOIN pm_ods_cl_cc_prl_d.cc_credential AS cr ON u.credentialid = cr.id AND cr.active=1 AND cr.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND u.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'        
        JOIN pm_ods_cl_cc_prl_d.cc_userrole AS ur ON u.id = ur.userid AND (ur.roleid = 1 OR ur.roleid = 4) AND ur.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
        JOIN pm_ods_cl_cc_prl_d.cc_contact AS c ON c.id = u.contactid AND c.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
        JOIN pm_ods_cl_cc_prl_d.ccx_lm_contactmethod AS cxm ON u.contactID = cxm.lm_contactid AND cxm.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' 
                AND ((LENGTH(cxm.lm_extension) = 5.0 AND (cxm.lm_extension LIKE ('7%') or cxm.lm_extension LIKE ('2%')))
                OR (LENGTH(cxm.lm_extension) = 7.0 AND (cxm.lm_extension LIKE ('727%') or cxm.lm_extension LIKE ('722%'))))
        JOIN PM_ODS_CL_CC_PRL_D.cc_contactcontact AS cc1 ON u.contactid=cc1.sourcecontactid 
                AND cc1.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND cc1.ODS_CDC_TRANS_TYPE NOT = 'D'        
        JOIN PM_ODS_CL_CC_PRL_D.cc_contact AS cc2 ON cc1.relatedcontactid = cc2.id AND cc2.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'         
        JOIN PM_ODS_CL_CC_PRL_D.cc_contact AS d on d.lm_departmentnumber = u.department AND d.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
        JOIN (
                SELECT

                        u.publicid AS nNumber,
                        //Returns value from segmentation attribute logic/concatenation                
                        CASE 
                        WHEN a1.description IS NULL AND a2.description IS NULL AND a3.description IS NULL THEN 'No segmentation attribute assigned'
                        WHEN a1.description IS NOT NULL AND a2.description IS NULL AND a3.description IS NULL THEN a1.description
                        WHEN a1.description IS NULL AND a2.description IS NOT NULL AND a3.description IS NULL THEN a2.description
                        WHEN a1.description IS NULL AND a2.description IS NULL AND a3.description IS NOT NULL THEN a3.description
                        WHEN a1.description IS NOT NULL AND a2.description IS NOT NULL AND a3.description IS NULL THEN concat(a1.description,', ', a2.description)
                        WHEN a1.description IS NOT NULL AND a2.description IS NULL AND a3.description IS NOT NULL THEN concat(a1.description,', ', a3.description)
                        WHEN a1.description IS NULL AND a2.description IS NOT NULL AND a3.description IS NOT NULL THEN concat(a2.description,', ', a3.description)
                        WHEN a1.description IS NOT NULL AND a2.description IS NOT NULL AND a3.description IS NOT NULL THEN concat(a1.description, a2.description, a3.description)
                        END AS segmentationAttribute  

                FROM
                        pm_ods_cl_cc_prl_d.cc_user AS u
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attributeUser AS auHC3 ON u.id = auHC3.userid 
                                AND auHC3.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND auHC3.attributeid='1401' AND auHC3.ODS_CDC_TRANS_TYPE != 'D'
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attributeUser AS auHC1 ON u.id = auHC1.userid 
                                AND auHC1.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND auHC1.attributeid='1501' AND auHC1.ODS_CDC_TRANS_TYPE != 'D'
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attributeUser AS auLC1 ON u.id = auLC1.userid 
                                AND auLC1.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND auLC1.attributeid='1301' AND auLC1.ODS_CDC_TRANS_TYPE != 'D'        
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attribute AS a1 ON a1.id=auHC3.attributeid and a1.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attribute AS a2 ON a2.id=auHC1.attributeid and a2.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_attribute AS a3 ON a3.id=auLC1.attributeid and a3.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'
                WHERE 
                        u.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59') AS s ON s.nNumber = u.publicid
        LEFT JOIN (
                SELECT
                        u.publicid as nNumber, g.name as regionName,                
                        //Provides row count to concate regions
                        ROW_NUMBER() OVER(PARTITION BY u.publicid ORDER BY regionName) AS rn
                FROM 
                        pm_ods_cl_cc_prl_d.cc_user AS u        
                        JOIN pm_ods_cl_cc_prl_d.cc_credential AS cr ON u.credentialid = cr.id AND cr.active=1 AND u.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' AND cr.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59'              
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_groupUser AS gu on gu.userID = u.id and gu.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59' and gu.groupID in ('2202','2302','2303','2304','2402') and gu.ODS_CDC_TRANS_TYPE != 'D'
                        LEFT JOIN pm_ods_cl_cc_prl_d.cc_group AS g on g.ID = gu.groupID and g.ODS_EXP_ROW_DTM = '9999-12-31 23:59:59') AS r ON u.publicid = r.nNumber

    GROUP BY u.publicid,d.name,fullName,Office,u.jobtitle,formattedExtension,
s.segmentationAttribute,expectedZeroOut

【问题讨论】:

我看到 8 列.. 9 组来自哪里? 首先不要在GROUP BY 上使用数字,这会给错误的发生提供很大的空间,就像您在group by 上有8 列但9 列一样 一般来说,您希望GROUP BYs 列出的列不超过~5 列。至少我可能会在 JOINed 子查询(你应该绝对命名)周围添加另一层,它正在执行聚合。 有太多错误,我认为最好向我们展示您的数据库架构、一些示例数据和预期输出。请阅读How-to-Ask 这里是START 了解如何提高问题质量并获得更好答案的好地方。 已更新以包含实际代码 【参考方案1】:

无论如何,不​​要使用列的位置进行聚合。


select      userid,department,fullname,office,title,extension

           ,  max (case rn when 1 then        region else '' end)
           || max (case rn when 2 then ',' || region else '' end)
           || max (case rn when 3 then ',' || region else '' end)
           || max (case rn when 4 then ',' || region else '' end) as location

           ,max (case when region = 'West' and DEPARTMENT = 10 then 'West_10' end)    as team

from       (select      e.*
                       ,row_number() over
                        (
                            partition by    userid,department,fullname,office,title,extension 
                            order by        regionname
                        ) as rn

            from        employee
            ) 

group by    userid,department,fullname,office,title,extension
;

【讨论】:

现在我收到“无法嵌套聚合操作”的错误。 @BDMorrissette,我的错,我们不能在创建 team 的表达式中使用 location。让我解决这个问题, @BDMorrissette,已修复,我也不确定 team 定义的逻辑 谢谢,我用我的实际代码更新了原始帖子,不幸的是团队内部的逻辑(实际列名是 exctedZeroOut)相当广泛。有超过 100 种不同的排列,所以我需要一些可以使用位置的东西。有什么办法吗? @BDMorrissette:如果regionMAX(CASE.. 的结果,它永远不会起作用,因为它是一个逗号分隔的列表,并且您将它与单个值进行比较。似乎您可以改用基列r.regionName

以上是关于在非聚合中使用聚合结果导致 GROUP BY 出现问题的主要内容,如果未能解决你的问题,请参考以下文章

聚合函数 和 group by

所选项目不必出现在 GROUP BY 子句中或在聚合函数中使用

PostgreSQL - 必须出现在 GROUP BY 子句中或在聚合函数中使用

性能调优8:分组聚合 - group by

Postgresql 错误:列必须出现在 GROUP BY 子句中或在聚合函数中使用

GroupingError:错误:列必须出现在 GROUP BY 子句中或在聚合函数中使用