2008-11-04 73 views
3

好的。我有一個如下所示的查詢:COALESCE SUM GROUP?

SELECT 
    SUM(`order_items`.`quantity`) as `count`, 
    `menu_items`.`name` 
FROM 
    `orders`, 
    `menu_items`, 
    `order_items` 
WHERE 
    `orders`.`id` = `order_items`.`order_id` AND 
    `menu_items`.`id` = `order_items`.`menu_item_id` AND 
    `orders`.`date` >= '2008-11-01' AND 
    `orders`.`date` <= '2008-11-30' 
GROUP BY 
    `menu_items`.`id` 

此查詢的目的是顯示在給定日期範圍內出售的物品數量。雖然這有效,但我現在需要它顯示0count,如果某個特定商品在日期範圍內沒有銷售。我嘗試在SUM附近使用COALESCE,但這並沒有成功,我也沒有真正期待它。總之,有人知道我會如何去完成這個?我有這樣一個時刻,我覺得我應該知道這一點,但我想不起來。

乾杯

回答

5

如果將日期條件置於JOIN子句中,則可以在沒有任何子查詢的情況下完成此操作。

下面是我在MySQL 5.0上測試的代碼。

SELECT m.name, COALESCE(SUM(oi.quantity), 0) AS count 
FROM menu_items AS m 
    LEFT OUTER JOIN (
    order_items AS oi JOIN orders AS o 
     ON (o.id = oi.order_id) 
) ON (m.id = oi.menu_item_id 
     AND o.`date` BETWEEN '2008-11-01' AND '2008-11-30') 
GROUP BY m.id; 

輸出:

+--------+-------+ 
| name | count | 
+--------+-------+ 
| bread |  2 | 
| milk |  1 | 
| honey |  2 | 
| cheese |  0 | 
+--------+-------+ 

這裏的DDL和設置代碼,在MySQL味:

DROP TABLE IF EXISTS menu_items; 
CREATE TABLE menu_items (
    id   INT PRIMARY KEY, 
    name   VARCHAR(10) 
) TYPE=InnoDB; 

DROP TABLE IF EXISTS orders; 
CREATE TABLE orders (
    id   INT PRIMARY KEY, 
    `date`  DATE 
) TYPE=InnoDB; 

DROP TABLE IF EXISTS order_items; 
CREATE TABLE order_items (
    order_id  INT, 
    menu_item_id INT, 
    quantity  INT, 
    PRIMARY KEY (order_id, menu_item_id), 
    FOREIGN KEY (order_id) REFERENCES orders(id), 
    FOREIGN KEY (menu_item_id) REFERENCES menu_items(id) 
) TYPE=InnoDB; 

INSERT INTO menu_items VALUES 
    (1, 'bread'), 
    (2, 'milk'), 
    (3, 'honey'), 
    (4, 'cheese'); 

INSERT INTO orders VALUES 
    (1, '2008-11-02'), 
    (2, '2008-11-03'), 
    (3, '2008-10-29'); 

INSERT INTO order_items VALUES 
    (1, 1, 1), 
    (1, 3, 1), 
    (2, 1, 1), 
    (2, 2, 1), 
    (2, 3, 1), 
    (3, 4, 10); 
3

蘭迪的答案是接近,但where語句刪除這些項目不在該日期範圍內的任何部分訂單的任何提及。

請注意,「左連接」不同於以已完成的方式(即內連接)在where子句中鏈接表。我建議你閱讀不同類型的SQL連接(內部,外部,交叉)。

在本質上,您需要將您從Randy的查詢中獲得的數據與源項目列表中的數據加入。使用子查詢將做到這一點:

SELECT 
    name 
    , nvl(count, 0) as count 
FROM 
    menu_items items 
    LEFT JOIN (
     SELECT 
      menu_items.id 
      , SUM(order_items.quantity) as count 
     FROM 
      menu_items 
      LEFT JOIN order_items ON menu_items.id = order_items.menu_item_id 
      LEFT JOIN orders ON orders.id = order_items.order_id 
     WHERE 
      "date" between to_date('2008-11-01','YYYY-MM-DD') and to_date('2008-11-30','YYYY-MM-DD') 
     GROUP BY 
      menu_items.id 
    ) counts on items.id = counts.id; 

這是Oracle 10g中BTW。我懷疑你使用的是Oracle,所以你需要轉換成你自己的數據庫。

運行測試顯示如下:

SQL> create table menu_items (id number, name varchar2(10)); 
create table order_items (order_id number, menu_item_id number, quantity number); 
create table orders (id number, "date" date); 

Table created. 

SQL> 
Table created. 

SQL> 
Table created. 

SQL> 
insert into menu_items values (1, 'bread'); 
insert into menu_items values (2, 'milk'); 
insert into menu_items values (3, 'honey'); 
insert into menu_items values (4, 'cheese'); 
SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> 
insert into orders values (1, to_date('2008-11-02', 'YYYY-MM-DD')); 
insert into orders values (2, to_date('2008-11-03', 'YYYY-MM-DD')); 
insert into orders values (3, to_date('2008-10-29', 'YYYY-MM-DD'));SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> 
insert into order_items values (1, 1, 1); 
insert into order_items values (1, 3, 1); 
1 row created. 

SQL> 
1 row created. 

SQL> 
insert into order_items values (2, 1, 1); 
insert into order_items values (2, 2, 1); 
insert into order_items values (2, 3, 1); 

insert into order_items values (3, 4, 10); 
1 row created. 

SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> 
1 row created. 

SQL> SQL> 

1 row created. 

SQL> 
SELECT 
    name 
    , nvl(count, 0) as count 
FROM 
    menu_items items 
    LEFT JOIN (
     SELECT 
      menu_items.id 
      , SUM(order_items.quantity) as count 
     FROM 
      menu_items 
      LEFT JOIN order_items ON menu_items.id = order_items.menu_item_id 
      LEFT JOIN orders ON orders.id = order_items.order_id 
     WHERE 
      "date" between to_date('2008-11-01','YYYY-MM-DD') and to_date('2008-11-30','YYYY-MM-DD') 
     GROUP BY 
      menu_iteSQL> 2 3 4 5 6 7 ms.id 
    ) counts on items.id = counts.id; 8 9 10 11 12 13 14 15 16 17 18 

NAME   COUNT 
---------- ---------- 
bread    2 
milk    1 
honey    2 
cheese    0 

SQL> 
drop table menu_items; 
drop table order_items; 
drop table orders;SQL> 
Table dropped. 

SQL> 
Table dropped. 

SQL> 

Table dropped. 

SQL> 

PS:這是不好的做法,使用「日期」作爲列名,因爲它是(在大多數情況下)一類的名稱,並可能導致問題的查詢和解析。

+0

很划算,傑米。 1比我的子查詢更少,而且更合理。只有需要更改MySQL的東西纔會取出Oracle的日期功能。 +1 – Randy 2008-11-04 23:56:47