0

我有两张桌子。

“商店”表是一个人口统计表,具有以下字段:

ID、ParentID、ConsolidationType

ID 是给定商店的唯一标识符。

ParentID 可以为 NULL 或包含其父商店的 ID(如果它的 ConsolidationType 为“Secondary”)。

ConsolidationType 为 NULL、“Primary”或“Secondary”。

“销售”表具有以下字段:

StoreID、SalesDate、SalesAmount

StoreID 是指 Store 表中的一个 ID。


我试图在单个查询的单行中获取给定商店的总合并销售额和单独销售额。我编写了如下 SQL 查询:

SELECT 
Store.ID AS 'Store ID',
SUM(IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)) AS 'Individual Sales',
SUM(IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1 AND YEAR(secondaries.SalesDate) = 2012 AND QUARTER(secondaries.SalesDate) = 1,main.SalesAmount + secondaries.SalesAmount,0) AS 'Consolidated Sales'
FROM Store 
LEFT JOIN Sales AS 'main' ON Store.ID = main.StoreID 
LEFT JOIN Sales AS 'secondaries' ON Store.ParentID = secondaries.StoreID 
GROUP BY Store.ID

我无法弄清楚为什么这不能按预期工作。我错过了什么?我的逻辑有什么问题?

4

2 回答 2

1

问题是您的查询正在生成笛卡尔积(类似)结果集。

基本上,对于来自“辅助”的每个匹配行,“主”中的一行会重复多次。

要获得您想要的结果,只需加入 sales 表一次,并匹配 StoreID 和 ParentID。

要获取Individual Sales,仅包含在 StoreID 匹配的 SUM 行中,如下所示:

SELECT Store.ID AS `Store ID`
     , SUM(IF(main.StoreID = Store.ID,
       IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
       ,0)) AS `Individual Sales`
     , SUM(
       IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
       ) AS `Consolidated Sales`
  FROM Store 
  LEFT JOIN Sales AS `main` ON main.StoreID = Store.ID OR main.StoreID = Store.ParentID
 GROUP BY Store.ID

更新

我的错。(DOH!)ParentIDStore桌子上,而不是Sales桌子上。

上面的查询没有返回指定的结果。(正在处理它。)

我想你已经有了解决方案......

使用该ParentID列代替表中的IDStore。如果 ParentID 列为 NULL,我们使用该ID列中的值。

SELECT IFNULL(Store.ParentID,Store.ID) AS `Store ID`
     , SUM(IF(main.StoreID = Store.ID,
       IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
       ,0)) AS `Individual Sales`
     , SUM(
       IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
       ) AS `Consolidated Sales`
  FROM Store s
  LEFT JOIN Sales AS `main` ON main.StoreID = Store.ID OR main.StoreID = Store.ParentID
 GROUP BY IFNULL(Store.ParentID,Store.ID)


此查询返回指定的结果集:

SELECT t.StoreID AS `Store ID`
     , SUM(IF(t.source='p',
       IF(YEAR(t.SalesDate) = 2012 AND QUARTER(t.SalesDate) = 1,t.SalesAmount,0)
       ,0)) AS `Individual Sales`
     , SUM(
       IF(YEAR(t.SalesDate) = 2012 AND QUARTER(t.SalesDate) = 1,t.SalesAmount,0)
       ) AS `Consolodiated Sales`
  FROM (    
         SELECT 'p' AS source
              , a.StoreID
              , a.SalesDate
              , a.SalesAmount
           FROM Sales a
          UNION ALL
         SELECT 's' AS source
              , s.ParentID
              , b.SalesDate
              , b.SalesAmount
           FROM Sales b
           JOIN Store s ON s.ID = b.StoreID
          WHERE s.ParentID IS NOT NULL
       ) t
 GROUP BY t.StoreID
 ORDER BY t.StoreID

这不是最有效的,内联视图(或“派生表”)按销售表的大小排列。将日期的谓词下推到内联视图中,或者在派生表中按月或季度汇总会更有效。

我更有可能将“季度”作为结果集的一部分返回,以允许我提取超过四分之一。

SELECT t.StoreID AS `Store ID`
     , t.SalesQuarter
     , SUM(IF(t.source='p',t.SalesAmount,0)) AS `Individual Sales`
     , SUM(t.SalesAmount) AS `Consolodiated Sales`
  FROM (    
         SELECT 'p' AS source
              , a.StoreID
              , ADDDATE(MAKEDATE(YEAR(a.SalesDate),1), INTERVAL FLOOR(MONTH(a.SalesDate)/4) QUARTER) AS SalesQuarter
              , SUM(a.SalesAmount) AS SalesAmount
           FROM Sales a
      --    WHERE a.SalesDate >= '2012-01-01'
      --      AND a.SalesDate < '2012-04-01'
          GROUP BY a.StoreID, SalesQuarter
          UNION ALL
         SELECT 's' AS source
              , s.ParentID
              , ADDDATE(MAKEDATE(YEAR(b.SalesDate),1), INTERVAL FLOOR(MONTH(b.SalesDate)/4) QUARTER) AS SalesQuarter
              , SUM(b.SalesAmount) AS SalesAmount
           FROM Sales b
           JOIN Store s ON s.ID = b.StoreID
          WHERE s.ParentID IS NOT NULL
      --      AND a.SalesDate >= '2012-01-01'
      --      AND a.SalesDate < '2012-04-01'
          GROUP BY s.ParentID, SalesQuarter
       ) t
 GROUP BY t.StoreID, t.SalesQuarter
 ORDER BY t.StoreID, t.SalesQuarter
于 2012-08-22T18:29:00.523 回答
0

我通常尝试将过滤逻辑保留在WHERE子句中。您的原始查询可能有太多JOINS,并且没有孩子的情况可能无法满足您的期望。下面的IS NULL检查WHERE允许没有孩子的商店。

SELECT
  s.ID
  , SUM(s.SalesAmount) AS `Individual Sales`
  , SUM(s.SalesAmount) + SUM(c.SalesAmount) AS `Consolidated Sales`
FROM Store AS s
LEFT OUTER JOIN Store AS c ON c.ParentID = s.ID
WHERE YEAR(s.SalesDate) = 2012 AND QUARTER(s.SalesDate) = 1
  AND (c.SalesDate IS NULL OR
    (YEAR(c.SalesDate) = 2012 AND QUARTER(c.SalesDate) = 1))
GROUP BY s.ID
于 2012-08-22T18:58:22.407 回答