2011-05-09 129 views
2

我無法獲取需要生成的報告的SQL。我有以下設置(的等價物):執行兩個GROUP BY的SQL查詢?

  • 一個表articles(字段,如姓名,manufacturer_id等)。
  • 表格sales
    • FK to文章叫article_id
    • 一個整數稱爲amount
    • 一個date
    • 的字段名爲type。我們可以假定它是一個字符串,它可以有3個已知值 - 'morning''evening''night'

我想產生聚合的銷售報告,給定一個開始日期和結束日期:

+--------------+---------------+--------------+-------------+ 
| article_name | morning_sales | evening_sales| night_sales | 
+--------------+---------------+--------------+-------------+ 
| article 1 |    0 |   12 |   2 | 
| article 2 |   80 |   3 |   0 | 
...   ...    ...   ...   ... 
| article n |   37 |   12 |   1 | 
+--------------+---------------+--------------+-------------+ 

我想盡可能有效地做到這一點。到目前爲止,我已經能夠生成一個查詢,它會給我一種類型的銷售(早上,晚上或晚上),但我無法同時爲多種類型進行銷售。它甚至有可能嗎?

這是我到目前爲止;它會給我的商品名,上午銷量在一定時期內的所有文章的 - 換句話說,該報告的前兩列:

SELECT articles.name as article_name, 
     SUM(sales.amount) as morning_sales, 
FROM "sales" 
INNER JOIN articles ON articles.id = sales.articles_id 
WHERE (sales.date >= '2011-05-09' 
    AND sales.end_date <= '2011-05-16' 
    AND sales.type = 'morning' 
) 
GROUP BY sales.article_id 

我想我可以爲傍晚和晚上做同樣的,但文章會有所不同;例如,一些文章可能在早上銷售,但不在晚上銷售。

  • 如果我必須爲每個銷售類型提出1個請求,我該如何「混合搭配」我將獲得的不同文章列表?
  • 有沒有更好的辦法做到這一點(也許有些子查詢)?

同樣,我可以建立一個查詢,讓我所有的早上,晚上和夜間銷售,按類型分組。我想我的問題是我需要做兩個GROUP BY才能得到這個報告。我不知道該怎麼做,如果可能的話。

我使用PostgreSQL作爲我的數據庫,但我想盡可能保持標準。如果有幫助,使用這個應用程序是一個Rails應用程序。

回答

4

幸運的是,您不需要使用數據庫格式執行多個查詢。這應該爲你工作:

SELECT 
    articles.name AS article_name 
    SUM(IF(sales.type = 'morning', sales.amount, 0.0)) AS morning_sales, 
    SUM(IF(sales.type = 'evening', sales.amount, 0.0)) AS evening_sales, 
    SUM(IF(sales.type = 'night', sales.amount, 0.0)) AS night_sales 
FROM sales 
    JOIN articles ON sales.article_id = articles.id 
WHERE 
    sales.date >= "2011-01-01 00:00:00" 
    AND sales.date < "2011-02-01 00:00:00" 
GROUP BY sales.article_id 

而且如果有其他類型,你就必須添加更多的列存在,或者簡單地通過增加這SELECT子句總結其他類型:

SUM(
    IF(sales.type IS NULL OR sales.type NOT IN ('morning', 'evening', 'night'), 
    sales.amount, 0.0 
) 
) AS other_sales 

以上是與MySQL兼容的。在Postgres的使用它,我想你可以到IF表述更改爲CASEexpressions,它應該像這樣(未經):

SELECT 
    articles.name AS article_name, 
    SUM(CASE WHEN sales.type = 'morning' THEN sales.amount ELSE 0.0 END) AS morning_sales, 
    SUM(CASE WHEN sales.type = 'evening' THEN sales.amount ELSE 0.0 END) AS evening_sales, 
    SUM(CASE WHEN sales.type = 'night' THEN sales.amount ELSE 0.0 END) AS night_sales 
FROM sales 
    JOIN articles ON sales.article_id = articles.id 
WHERE 
    sales.date >= "2011-01-01 00:00:00" 
    AND sales.date < "2011-02-01 00:00:00" 
GROUP BY sales.article_id 
+0

謝謝:)我一定是錯過了讀書的問題 – 2011-05-09 22:34:29

+0

感謝一個時很多!這幫了我很大的忙! – kikito 2011-05-10 07:27:15

2

兩個選項。

選項1.單與計算列加入了agreggation

​​

選項2.多個左聯接

select article_name = a.article_name , 
     morning_sales = sum(morning.amount) , 
     evening_sales = sum(evening.amount) , 
     night_sales = sum(night.amount ) , 
     other_sales = sum(other.amount ) , 
     total_sales = sum(total.amount ) 
from  articles a 
left join sales morning on morning.articles_id = a.articles_id 
          and morning.type  = 'morning' 
          and morning.date between @dtFrom and @dtThru 
left join sales evening on evening.articles_id = a.articles_id 
          and evening.type  = 'evening' 
          and evening.date between @dtFrom and @dtThru 
left join sales night on night.articles_id = a.articles_id 
          and night.type   = 'evening' 
          and night.date between @dtFrom and @dtThru 
left join sales other on other.articles_id = a.articles_id 
          and ( other.type is null 
           OR other.type not in ('morning','evening','night') 
          ) 
          and other.date between @dtFrom and @dtThru 
left join sales total on total.articles_id = a.articles_id 
          and total.date between @dtFrom and @dtThru 
group by a.article_name 
+0

相當不錯;我喜歡選項2背後的想法,作爲自連接的替代方案。但選項2有3個問題。 (1)您只選擇了一個值,文章名!您還需要從自聯接中選擇值。 (2)根據查詢的使用方式,可能需要列名。因此,查詢應該以 'Select a.article_name,Sum(morning.amount)MorningAmount,Sum(evening.amount)EveningAmount', (依此類推)開始。 (3)注意'sum(Total.amount)'總是等於'sum(a.Amount)',所以你有更多的自連接比你需要;完全離開總計。 – 2011-05-10 00:37:04

+0

+1表示可以選擇子選擇。 – 2011-05-10 00:38:55

+0

我的查詢與OP的例子相符。但是,如果您需要使用除列分組或聚合函數以外的列來修飾聚合結果集,則複雜程度會提高。有些人只是將它們添加到分組列表中,但根據我的經驗,這會導致......有趣的結果......當數據(像往常一樣)不如應有的那麼幹淨。 – 2011-05-10 00:51:40