按条件子查询

时间:2016-07-13 01:30:02

标签: mysql group-by sum

我正在规范某些表并遇到了一个我无法解决的问题。

旧的非规范化查询如下所示:

SELECT
      SUM(allorderlines.COUNT),
      products.NAME,
      products.VOLUME,
      people.NAME,
      people.ID,
      layout.POSTYPE,
      IF( allorders.TOTAL = allorders.DISCOUNT, 1, 0 ) AS ISFREE
   FROM
      allorderlines
         INNER JOIN allorders
            ON allorderlines.ORDERID = allorders.ORDERID
            INNER JOIN people
               ON allorders.EMPLOYEE = people.ID
            INNER JOIN layout
               ON allorders.POSID = layout.ID
         INNER JOIN products
            ON allorderlines.PRODUCT = products.ID 
   WHERE
      allorderlines.PRODUCT = ?
   GROUP BY
      people.ID,
      layout.POSTYPE,
      ISFREE
   ORDER BY
      layout.POSTYPE ASC,
      people.NAME,
      ISFREE ASC,
      products.NAME

这意味着我可以将结果分组到订单是否免费(即免费)。

在我的规范化版本中,我没有allorders表(allorders.TOTALallorders.DISCOUNT)中可用订单的总和。为了确定订单是否免费,我需要SUM(allorderlines.LINEPRICE)并查看它是否等于0.产品的行不会是0,但是具有订单贴现值的另一行将存在且等于如果订单总共是免费的产品总数:例如:

#Order 23123
 Line 1: 2000
 Line 2: 1000
 Line 3 (discount): -3000

Free: true

#Order 23124
 Line 1: 2000
 Line 2: 1000
 Line 3 (discount): -2000

Free: false

我无法弄清楚如何做到这一点并保留上述逻辑。我最接近的尝试是将ISFREE替换为:{/ p>

IF(SUM(allorderlines.LINEPRICE) = 0,1,0) AS ISFREE

但是这给了我一个“不能通过ISFREE分组” - 错误,大概是因为我试图分组在这种情况下无法获得的东西。

一个显而易见的解决方案是在allorders.LINEPRICE - 表中保存allorders的总和,但这将是多余的,我正试图摆脱它。

请注意,DISCOUNT值以前是正数,而订单行现在为负值。因此(allorders.TOTAL = allorders.DISCOUNT)= FREE。

编辑:为了澄清,结果集应该类似于:

people.ID     people.NAME    SUM(COUNT)      POSTYPE    ISFREE
3             A name         4               1          1
3             A name         24              1          0
3             A name         2               2          1
3             A name         7               2          0
6             Another name   2               1          1
6             Another name   93              1          0
6             Another name   6               2          1
6             Another name   193             2          0

每个人可以有0到4行,0表示在给定产品的任何POSTYPE都不以任何价格出售,4表示至少1个免费,1个出售给两个POSTYPES(截至撰写时仅有2种类型。

1 个答案:

答案 0 :(得分:1)

首先,让我们这样做。您正在寻找具有特定产品的任何订单。执行预查询以获取该产品的所有不同订单。然后加入按订单分组的订单行,以检测总免费网络订单。

最后,重新加入订单行和其他表格以获取您正在寻找的额外内容,但是按人,布局划分的组是免费标记,但按产品名称排序意味着显示所有产品订单的名称,但您的where子句仅查找ONE产品。

首先,首先是资格预审,还使用别名和长表名。

SELECT
      QualByProd.OrderID,
      SUM( AOL2.LinePrice ) as TotalOrder,
      COUNT(*) as LineItemCount
   FROM
      ( SELECT distinct AOL.OrderID
           from AllOrderLines AOL
           where AOL.Product = ? ) QualByProd
         JOIN AllOrderLines AOL2
            ON QualByProd.OrderID = AOL2.OrderID2
   GROUP BY
      QualByProd.OrderID

这将为您提供1)具有相关产品ID的每个订单,以及2)汇总整个订单中所有订单项的摘要,无论其是免费状态还是产品名称。但是在这一点上,它是每个合格订单的一条记录,总数(包括与合格产品相关的订单中的总订单项数)。现在,我们可以将整个查询作为原始内容的基础,例如......

SELECT
      PR.NAME ProductName,
      PR.VOLUME ProductVolume,
      P.NAME PersonName,
      P.ID PersonID,
      L.POSTYPE,
      IF( OkRecs.TotalOrder, 1, 0 ) AS ISFREE,
      OkRecs.LineItemCount
   FROM
      ( entire first query above by product ) as OkRecs
         JOIN AllOrderLines AOL3
            ON OkRecs.OrderID = AOL3.OrderID
         JOIN AllOrders AO
            ON OkRecs.OrderID = AO.OrderID
            INNER JOIN people P
               ON AO.EMPLOYEE = P.ID
            INNER JOIN layout L
               ON AO.POSID = L.ID
         INNER JOIN products PR
            ON AOL3.Product = PR.ID 
   WHERE
      AOL3.PRODUCT = ?
   ORDER BY
      L.POSTYPE,
      P.NAME,
      IF( OkRecs.TotalOrder, 1, 0 )
      PR.NAME

现在,您的分组表示汇总,但我认为您不希望这样。你可以让一个人有两个不同的订单...... 1个免费,5个付费的东西,总共6个订单。由于没有聚合,您可以按顺序排序。最后,免费物品。如果您想查看所有免费的订单,那么在所有POSType,个人和产品中,只需将IF()移动到第一个位置。