【问题标题】:Group By not functioning as desired分组方式未按预期运行
【发布时间】:2013-08-15 13:20:34
【问题描述】:

假设我有三个表——Orders、OrderDetails 和 ProductType——并且 Orders 表包含一个 Customer 列。我需要做的是编写一个查询,它将向我显示客户列表以及每个客户下了多少订单,以及按另一列显示和分组,这是一个基于特定类型产品的布尔值 - 比如说, 电话 - 按顺序排列。

例如,我们可能有:

客户 |订单数量 |包括电话
---------------------------------
詹姆逊 | 3 |是的
史密斯 | 5 |是的
韦伯 | 1 |是的
亚当斯 | 2 | |没有
詹姆森 | 1 |没有
史密斯 | 7 |没有
韦伯 | 2 |没有

但是,当我尝试为此编写查询时,我得到了多行具有相同的 Customer 和 IncludesPhone 值,每行具有不同的 NumOrders 值。为什么会这样?我的查询如下:

SELECT Customer, COUNT(Customer) AS NumOrders, CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END AS IncludesPhone
FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
GROUP BY Customer, Type
Order By IncludesPhone, Customer

【问题讨论】:

  • 如果您使用 OrderDetails 加入订单,则 COUNT 将为您提供已订购产品的数量,而不是订单数量。这就是你需要的?
  • @BogdanSahlean - S.M 的回答正是我所需要的。
  • 那么您的问题是错误的:“我需要做的是编写一个查询,该查询将向我显示客户列表以及每个客户下了多少订单”。你应该改写你的问题。

标签: sql sql-server-2008 group-by


【解决方案1】:

将分组改为

GROUP BY    Customer, 
            CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END

【讨论】:

    【解决方案2】:

    这个查询应该可以工作

    SELECT Customer, COUNT(Customer) AS NumOrders, 
    CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END AS IncludesPhone
    FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
    GROUP BY    Customer, 
    CASE WHEN (ProductType.Type = 'Phone') THEN 'Yes' ELSE 'No' END
    Order By IncludesPhone, Customer
    

    【讨论】:

      【解决方案3】:

      由于您同时对Customer 和Type 进行分组,因此您的查询会返回每种类型的每位客户的订单数。如果您只希望每个客户一行,您应该只按Customer 分组,然后使用类似这样的方法来确定给定客户是否购买了手机:

      SELECT Customer, COUNT(Customer) AS NumOrders, 
          CASE 
              WHEN SUM(CASE WHEN (ProductType.Type = 'Phone') THEN 1 ELSE 0 END) > 0 
              THEN 'Yes' 
          ELSE 'No' END AS IncludesPhone
      FROM Orders INNER JOIN OrderDetails INNER JOIN ProductType
      GROUP BY Customer
      Order By IncludesPhone, Customer
      

      内部总和基本上计算每个客户购买的手机数量。如果大于 0,则客户至少购买了一部手机,我们返回“是”。

      【讨论】:

        【解决方案4】:

        那是因为您按Type 列分组,所以可能有重复的行。例如,对于类型“电子邮件”和“个人”列,IncludesPhone 将为“否”,但当您按 Type 分组时,输出中将有两条记录。

        要解决此问题,您可以在 group by 子句中使用相同的表达式或使用子查询或 Common Table Expression:

        with cte as (
            select
                Customer,
                case when pt.Type = 'Phone' then 'Yes' else 'No' end as IncludesPhone
            from Orders as o
                inner join OrderDetails as od -- ???
                inner join ProductType as pt -- ???
        )
        select Customer, IncludesPhone, count(*) as NumOrders
        from cte
        group by Customer, IncludesPhone
        order by IncludesPhone, Customer
        

        在group by 子句中使用相同的表达式:

        select
            Customer,
            case when pt.Type = 'Phone' then 'Yes' else 'No' end as IncludesPhone,
            count(*) as NumOrders
        from Orders as o
            inner join OrderDetails as od -- ???
            inner join ProductType as pt -- ???
        group by Customer, case when pt.Type = 'Phone' then 'Yes' else 'No' end
        

        【讨论】:

          【解决方案5】:

          你可以试试这个查询:

          SELECT  x.Customer,x.NumOrders,
                  CASE WHEN x.NumOrders>0 AND EXISTS(
                      SELECT  *
                      FROM    Orders o
                      INNER JOIN OrderDetails od ON ...
                      INNER JOIN ProductType pt ON ...
                      WHERE   o.Customer=x.Customer
                      AND pt.Type = 'Phone'
                  ) THEN 1 ELSE 0 END IncludesPhone
          FROM
          (
              SELECT  Customer,COUNT(Customer) AS NumOrders
              FROM    Orders 
              GROUP BY Customer
          ) x
          Order By IncludesPhone, x.Customer;
          

          或者这个:

          SELECT  o.Customer, 
                  COUNT(o.Customer) AS NumOrders, 
                  MAX(CASE WHEN EXISTS
                  (
                      SELECT  *
                      FROM    OrderDetails od
                      JOIN    ProductType pt ON ...
                      WHERE   o.OrderID=od.OrderID -- Join predicated between Orders and OrderDetails table
                      AND     ProductType.Type = 'Phone'
                  ) THEN 1 ELSE 0 END) AS IncludesPhone
          FROM    Orders o
          GROUP BY Customer
          ORDER BY IncludesPhone, o.Customer
          

          【讨论】:

          • @AndriyM:我在 GROUP BY 中没有看到任何别名。请更具体。
          • 显然我看到了一些不存在的东西,抱歉。
          猜你喜欢
          • 2015-09-19
          • 1970-01-01
          • 2018-01-08
          • 2015-10-13
          • 1970-01-01
          • 1970-01-01
          • 2019-12-23
          • 2014-11-12
          • 1970-01-01
          相关资源
          最近更新 更多