2010-04-29 30 views
1

我想創造什麼樣的,我認爲是一個在線商店相對基本的報告,使用MySQL 45年5月1日使用MySQL來生成與彌補的差距每日銷售報告,通過貨幣

商店可以接收付款分組以多種貨幣。 我已經創建了一些包含數據的示例表,並且試圖生成一個按日期和貨幣分組的簡單表格結果集,以便我可以繪製這些數字。

我想查看每個日期可用的每種貨幣,如果當天沒有以該貨幣進行的銷售,結果爲0。 如果我可以得到這個工作,我想要做同樣的事情,但也按產品ID分組。

在我提供的樣本數據中,只有3種貨幣和2種產品ID,但實際上可以有任何數量的每種。

我可以按日期正確分組,但隨後當我通過貨幣添加分組時,我的查詢不會返回我想要的。

我基於我的作品this article

我的報表查詢,僅按日期分組:

SELECT calendar.datefield AS date, 
    IFNULL(SUM(orders.order_value),0) AS total_value 
FROM orders 
RIGHT JOIN calendar ON (DATE(orders.order_date) = calendar.datefield) 
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE(order_date)) FROM orders) AND (SELECT MAX(DATE(order_date)) FROM orders)) 
GROUP BY date 

現在按日期和貨幣分組:

SELECT calendar.datefield AS date, orders.currency_id, 
    IFNULL(SUM(orders.order_value),0) AS total_value 
FROM orders 
RIGHT JOIN calendar ON (DATE(orders.order_date) = calendar.datefield) 
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE(order_date)) FROM orders) AND (SELECT MAX(DATE(order_date)) FROM orders)) 
GROUP BY date, orders.currency_id 

我得到的結果(按日期和貨幣分組)

+------------+-------------+-------------+ 
| date  | currency_id | total_value | 
+------------+-------------+-------------+ 
| 2009-08-15 |   3 |  81.94 | 
| 2009-08-15 |   45 |  25.00 | 
| 2009-08-15 |   49 |  122.60 | 
| 2009-08-16 |  NULL |  0.00 | 
| 2009-08-17 |   45 |  25.00 | 
| 2009-08-17 |   49 |  122.60 | 
| 2009-08-18 |   3 |  81.94 | 
| 2009-08-18 |   49 |  245.20 | 
+------------+-------------+-------------+ 

結果I 想要

+------------+-------------+-------------+ 
| date  | currency_id | total_value | 
+------------+-------------+-------------+ 
| 2009-08-15 |   3 |  81.94 | 
| 2009-08-15 |   45 |  25.00 | 
| 2009-08-15 |   49 |  122.60 | 
| 2009-08-16 |   3 |  0.00 | 
| 2009-08-16 |   45 |  0.00 | 
| 2009-08-16 |   49 |  0.00 | 
| 2009-08-17 |   3 |  0.00 | 
| 2009-08-17 |   45 |  25.00 | 
| 2009-08-17 |   49 |  122.60 | 
| 2009-08-18 |   3 |  81.94 | 
| 2009-08-18 |   45 |  0.00 | 
| 2009-08-18 |   49 |  245.20 | 
+------------+-------------+-------------+ 

的架構和數據,我用我的測試:

CREATE TABLE orders 
(
    id INT PRIMARY KEY AUTO_INCREMENT, 
    order_date DATETIME, 
    order_id INT, 
    product_id INT, 
    currency_id INT, 
    order_value DECIMAL(9,2), 
    customer_id INT 
); 
INSERT INTO orders (order_date, order_id, product_id, currency_id, order_value, customer_id) 
    VALUES 
    ('2009-08-15 10:20:20', '123', '1', '45', '12.50', '322'), 
    ('2009-08-15 12:30:20', '124', '1', '49', '122.60', '400'), 
    ('2009-08-15 13:41:20', '125', '1', '3', '40.97', '324'), 
    ('2009-08-15 10:20:20', '126', '2', '45', '12.50', '345'), 
    ('2009-08-15 13:41:20', '131', '2', '3', '40.97', '756'), 

    ('2009-08-17 10:20:20', '3234', '1', '45', '12.50', '1322'), 
    ('2009-08-17 10:20:20', '4642', '2', '45', '12.50', '1345'), 
    ('2009-08-17 12:30:20', '23', '2', '49', '122.60', '3142'), 

    ('2009-08-18 12:30:20', '2131', '1', '49', '122.60', '4700'), 
    ('2009-08-18 13:41:20', '4568', '1', '3', '40.97', '3274'), 
    ('2009-08-18 12:30:20', '956', '2', '49', '122.60', '3542'), 
    ('2009-08-18 13:41:20', '443', '2', '3', '40.97', '7556'); 

CREATE TABLE currency 
    (
    id INT PRIMARY KEY, 
    name VARCHAR(255) 
); 
INSERT INTO currency (id, name) 
    VALUES 
    (3, 'Euro'), 
    (45, 'US Dollar'), 
    (49, 'CA Dollar'); 


CREATE TABLE calendar (datefield DATE); 

    DELIMITER | 
    CREATE PROCEDURE fill_calendar(start_date DATE, end_date DATE) 
    BEGIN 
    DECLARE crt_date DATE; 
    SET crt_date=start_date; 
    WHILE crt_date < end_date DO 
     INSERT INTO calendar VALUES(crt_date); 
     SET crt_date = ADDDATE(crt_date, INTERVAL 1 DAY); 
    END WHILE; 
    END | 
    DELIMITER ; 

CALL fill_calendar('2008-01-01', '2011-12-31'); 

回答

3

你會發現很難得到你想要有結果,除非你把一個虛擬的順序進入系統每天每種貨幣(可以在fill_calendar例程中輕鬆完成測試)。

現在,你想要的是加入日曆,訂單和貨幣使用一個共同的鏈接;但沒有這樣的鏈接(您從日曆到訂單和訂單鏈接到貨幣,但從日曆到貨幣沒有鏈接)。

如果您創建了這些虛擬訂單,那麼您不需要更改模式;數據本身會提供所需的鏈接。否則,你可能不得不改變一下模式。

2

我發佈這個作爲答案,因爲它可能是相當大的評論。 感謝馬克指引我在正確的方向。 馬克的回答工作,但意味着一個模式切換到日曆表,我並不熱衷於,因爲我可能需要的報告將在未來更靈活(如組由PRODUCT_ID

這工作 - 但它可能不夠高雅。我會留下這個問題「未回答」幾天,看看有沒有人能想出更好的解決方案。

其他架構和數據(另外一個產品表):

現在使用此查詢我得到的答案我想:

SELECT cal.date AS date, currency.name AS currency, products.name AS product, 
    IFNULL(SUM(orders.order_value),0) AS total_value 
FROM orders 
RIGHT JOIN 
(
SELECT cal.datefield AS date, cur.id AS currency, prod.id AS product 
FROM calendar cal 
CROSS JOIN currency cur 
CROSS JOIN products prod 
) cal 
ON (DATE(orders.order_date) = cal.date) 
    AND orders.currency_id = cal.currency 
    AND orders.product_id = cal.product 
JOIN currency ON cal.currency = currency.id 
JOIN products ON cal.product = products.id 
WHERE (cal.date BETWEEN (SELECT MIN(DATE(order_date)) FROM orders) AND (SELECT MAX(DATE(order_date)) FROM orders)) 
GROUP BY date, cal.currency,cal.product 

這讓我對所有天所有數據點如果不存在,則爲零。

+------------+-----------+--------+-------------+ 
| date  | currency | product| total_value | 
+------------+-----------+--------+-------------+ 
| 2009-08-15 | Euro  | Widget |  40.97 | 
| 2009-08-15 | Euro  | Midget |  40.97 | 
| 2009-08-15 | Euro  | Gidget |  0.00 | 
| 2009-08-15 | US Dollar | Widget |  12.50 | 
| 2009-08-15 | US Dollar | Midget |  12.50 | 
| 2009-08-15 | US Dollar | Gidget |  0.00 | 
| 2009-08-15 | CA Dollar | Widget |  122.60 | 
| 2009-08-15 | CA Dollar | Midget |  0.00 | 
| 2009-08-15 | CA Dollar | Gidget |  0.00 | 
| 2009-08-16 | Euro  | Widget |  0.00 | 
| 2009-08-16 | Euro  | Midget |  0.00 | 
| 2009-08-16 | Euro  | Gidget |  0.00 | 
| 2009-08-16 | US Dollar | Widget |  0.00 | 
| 2009-08-16 | US Dollar | Midget |  0.00 | 
| 2009-08-16 | US Dollar | Gidget |  0.00 | 
| 2009-08-16 | CA Dollar | Widget |  0.00 | 
| 2009-08-16 | CA Dollar | Midget |  0.00 | 
| 2009-08-16 | CA Dollar | Gidget |  0.00 | 
| 2009-08-17 | Euro  | Widget |  0.00 | 
| 2009-08-17 | Euro  | Midget |  0.00 | 
| 2009-08-17 | Euro  | Gidget |  0.00 | 
| 2009-08-17 | US Dollar | Widget |  12.50 | 
| 2009-08-17 | US Dollar | Midget |  12.50 | 
| 2009-08-17 | US Dollar | Gidget |  0.00 | 
| 2009-08-17 | CA Dollar | Widget |  0.00 | 
| 2009-08-17 | CA Dollar | Midget |  122.60 | 
| 2009-08-17 | CA Dollar | Gidget |  0.00 | 
| 2009-08-18 | Euro  | Widget |  40.97 | 
| 2009-08-18 | Euro  | Midget |  40.97 | 
| 2009-08-18 | Euro  | Gidget |  0.00 | 
| 2009-08-18 | US Dollar | Widget |  0.00 | 
| 2009-08-18 | US Dollar | Midget |  0.00 | 
| 2009-08-18 | US Dollar | Gidget |  0.00 | 
| 2009-08-18 | CA Dollar | Widget |  122.60 | 
| 2009-08-18 | CA Dollar | Midget |  122.60 | 
| 2009-08-18 | CA Dollar | Gidget |  0.00 | 
+------------+-----------+--------+-------------+ 

它使用一個子查詢,我認爲不是很高性能的一個JOIN,但它工作在這個小數據集 - 我會產生更多的數據,看看它是如何去。