按T-SQL与MySQL分组(单列)

时间:2014-05-07 16:59:41

标签: sql sql-server tsql group-by aggregate

我是SQL Server的新手/用于MySQL数据库,我遇到了一个我从未遇到过MySQL的问题。我希望提取所有当前的保单号码,公司/所属人员的姓名,总保费,以及他们是否拥有我们所称的设备故障'覆盖。这一切都很简单,我遇到的问题是分组。我想只分组一列,也就是一个不同的政策编号,公司名称,保险费总和(可能有几个保费金额,无论是负面的还是正面的,所以我想总结这些,看看真正的总数是多少),以及设备故障的简单“是”或“否”列。

这是我正在运行的查询:

SELECT pol_num as policy_number, 
insd_name as insureds_name, 
SUM(amt) as 'total_premium',
(SELECT
    CASE 
        WHEN cvg_desc = 'Equipment Breakdown'
            THEN 'Y'
        ELSE 'N'    
    END) as 'equipment_breakdown'
FROM bapu.dbo.fact_prem
WHERE '2014-05-06' between d_pol_eff and d_pol_exp
AND amt_type = 'Premium'
AND amt_desc = 'Written Premium'
GROUP BY pol_num
ORDER BY policy_number

我收到一条错误消息,说我需要按照insd_name和cvg_desc分组,但我不想这样,因为它给了我重复的政策号码。

以下是我将其告诉我的一切分组后得到的一个例子:

policy_number   insureds_name       total_premium      equipment_breakdown

001             company a           0.00               n
001             company a           25,000.00          n
001             company a          -10,000.00          n
002             company b           100.00             y
002             company b           10,000.00          y

以下是我想要的结果示例:

policy_number   insureds_name       total_premium      equipment_breakdown

001             company a           15,000.00          n
002             company b           10,100.00          y

基本上,我只想按保单编号分组并汇总保费金额。以上是我在MySQL中实现这一目标的方法,如何在SQL Server中实现我想要的结果?

由于

4 个答案:

答案 0 :(得分:1)

MySQL并不要求所有非聚合字段都包含在GROUP BY子句中,即使不这样做也会产生意外结果。 SQL Server需要这样做,因此您不得不决定如何处理给定insd_name的多个pol_num值,您可以使用MAX()MIN(),或者如果值始终相同,只需将它们添加到GROUP BY

即可
SELECT  pol_num AS policy_number
      , MAX(insd_name) AS insureds_name
      , SUM(amt) AS 'total_premium'
      , MAX(CASE WHEN cvg_desc = 'Equipment Breakdown' THEN 'Y'
             ELSE 'N'
        END) AS 'equipment_breakdown'
FROM    bapu.dbo.fact_prem
WHERE   '2014-05-06' BETWEEN d_pol_eff AND d_pol_exp
        AND amt_type = 'Premium'
        AND amt_desc = 'Written Premium'
GROUP BY pol_num
ORDER BY policy_number

或者:

SELECT  pol_num AS policy_number
      , insd_name AS insureds_name
      , SUM(amt) AS 'total_premium'
      , CASE WHEN cvg_desc = 'Equipment Breakdown' THEN 'Y'
             ELSE 'N'
        END AS 'equipment_breakdown'
FROM    bapu.dbo.fact_prem
WHERE   '2014-05-06' BETWEEN d_pol_eff AND d_pol_exp
        AND amt_type = 'Premium'
        AND amt_desc = 'Written Premium'
GROUP BY pol_num
       , insd_name
       , CASE WHEN cvg_desc = 'Equipment Breakdown' THEN 'Y'
             ELSE 'N'
        END
ORDER BY policy_number

答案 1 :(得分:1)

看起来cvg_desc列可能会让你感到烦恼。您希望按照Y语句中生成的NCASE进行分组,但SQL服务器按原始cvg_desc列进行分组。您可以通过在分组之前解析CASE语句的方式来解决此问题。例如,将主查询包装在公用表表达式(CTE)中,这类似于内联视图。然后,将设备细分列减少到YN,CTE的SUM聚合premium后续查询应该会为您提供所需的结果:

WITH Policies(policy_number, insureds_name, premium, equipment_breakdown) AS
(
    SELECT 
        pol_num
        ,insd_name
        ,amt
        ,(CASE WHEN cvg_desc = 'Equipment Breakdown' THEN 'Y' ELSE 'N' END) 
            AS 'equipment_breakdown'
    FROM
        bapu.dbo.fact_prem
    WHERE 
        '2014-05-06' BETWEEN d_pol_eff AND d_pol_exp
        AND 
        amt_type = 'Premium'
        AND 
        amt_desc = 'Written Premium'
)
SELECT
    policy_number
    ,insureds_name
    ,SUM(premium) AS total_premium
    ,equipment_breakdown
FROM
    Policies
GROUP BY
    policy_number
    ,insureds_name
    ,equipment_breakdown

答案 2 :(得分:0)

您需要在您不想分组的字段上使用汇总功能。一个简单的使用方法是MAX,适用于大多数类型;

SELECT pol_num as policy_number, 
MAX(insd_name) as insureds_name, 
SUM(amt) as 'total_premium',
(SELECT
    CASE 
        WHEN MAX(cvg_desc) = 'Equipment Breakdown'
            THEN 'Y'
        ELSE 'N'    
    END) as 'equipment_breakdown'
FROM bapu.dbo.fact_prem
WHERE '2014-05-06' between d_pol_eff and d_pol_exp
AND amt_type = 'Premium'
AND amt_desc = 'Written Premium'
GROUP BY pol_num
ORDER BY policy_number

SQL Server想要这个的原因是它喜欢给出确定性答案,例如

column_a | column_b
1        | 1
1        | 2

...仅由column_a分组将在MySQL中给出1或2作为column_b的答案,而SQL Server希望您明确告诉它使用哪一个。

答案 3 :(得分:0)

我可能会写如下 - 没有测试

SELECT pol_num as policy_number, 
insd_name as insureds_name, 
SUM(amt) as total_premium
CASE 
    WHEN cvg_desc = 'Equipment Breakdown'
        THEN 'Y'
    ELSE 'N'    
END as equipment_breakdown
FROM bapu.dbo.fact_prem
WHERE '2014-05-06' between d_pol_eff and d_pol_exp
AND amt_type = 'Premium'
AND amt_desc = 'Written Premium'

GROUP BY 
pol_num, policy_number, 
CASE 
    WHEN cvg_desc = 'Equipment Breakdown'
        THEN 'Y'
    ELSE 'N'    
END
ORDER BY policy_number