0

私は2つのテーブルを持っています。

「Store」テーブルは人口統計テーブルで、次のようなフィールドがあります。

ID、ParentID、ConsolidationType

ID は、特定のストアの一意の識別子です。

親ストアの ConsolidationType が「Secondary」の場合、ParentID は NULL であるか、その親ストアの ID を含んでいる可能性があります。

ConsolidationType は、NULL、'Primary'、または 'Secondary' のいずれかです。

「Sales」テーブルには、次のようなフィールドがあります。

StoreID、SalesDate、SalesAmount

StoreID は、Store テーブル内の ID を参照します。


1 つのクエリの 1 つの行で、特定の店舗の総売上高と個別売上高を取得しようとしています。次のような 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

問題は、クエリがデカルト積 (-like) の結果セットを生成していることです。

基本的に、「メイン」の行は、「セカンダリ」の一致する行ごとに複数回繰り返されます。

必要な結果を得るには、sales テーブルに 1 回だけ参加し、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の代わりに列を使用します。ParentID 列が NULL の場合、列の値を使用します。IDStoreID

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

これは最も効率的ではありません。インライン ビュー (または「派生テーブル」) は、Sales テーブルのサイズのオーダーです。日付の述語をインライン ビューにプッシュするか、派生テーブルで月または四半期ごとに要約する方が効率的です。

結果セットの一部として「四半期」を返す可能性が高く、複数の四半期を取得できるようになります。

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 に答える