1

MySQL 5.1.45を使用して、オンラインストアの比較的基本的なレポートと思われるものを作成しようとしています。

ストアは複数の通貨で支払いを受け取ることができます。データを使用していくつかのサンプルテーブルを作成し、これらの数値をグラフ化できるように、日付と通貨でグループ化された簡単な表形式の結果セットを生成しようとしています。

日付ごとに利用可能な各通貨を確認したいのですが、その日のその通貨での売上がなかった場合は結果が0になります。 それを機能させることができれば、同じことをしたいのですが、製品IDごとにグループ化されています。

私が提供したサンプルデータでは、3つの通貨と2つの製品IDしかありませんが、実際にはそれぞれの数はいくつでもかまいません。

日付で正しくグループ化できますが、通貨でグループ化を追加すると、クエリで必要なものが返されません。

私はこの記事に基づいて作業を行いました。

日付のみでグループ化されたレポートクエリ:

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 |
+------------+-------------+-------------+

私が望む結果:

+------------+-------------+-------------+
| 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');
4

2 に答える 2

3

毎日すべての通貨に対してシステムにダミーの注文を入れない限り、希望する結果を得るのが難しいことに気付くでしょう (これは、テストのために fill_calendar ルーチンで簡単に実行できます)。

今、あなたが望むのは、共通のリンクを使用してカレンダー、注文、および通貨を結合することです。しかし、そのようなリンクはありません (カレンダーから注文へのリンクと注文から通貨へのリンクがありますが、カレンダーから通貨へのリンクはありません)。

これらのダミーの注文を作成した場合、スキーマを変更する必要はありません。データ自体が必要なリンクを提供します。それ以外の場合は、おそらくスキーマを少し変更する必要があります。

于 2010-04-30T11:32:27.103 に答える
2

コメントにはかなり大きい可能性があるため、これを回答として投稿しています。私を正しい方向に向けてくれたマークに感謝します。マークの答えはうまくいきましたが、今後レポートをより柔軟にする必要があるかもしれないので、私が熱心ではなかったカレンダーテーブルへのスキーマ変更を意味しました(例: product_idによるグループ化)

これは機能しますが、エレガントではないかもしれません。誰かがより良い解決策を思い付くことができるかどうかを確認するために、この質問を数日間「未回答」のままにしておきます.

追加のスキーマとデータ (製品テーブルの追加):

CREATE TABLE products
  (
    id INT PRIMARY KEY,
    name VARCHAR(255)
  );
INSERT INTO products (id, name)
  VALUES
  (1, 'Widget'),
  (2, 'Midget'),
  (3, 'Gidget');

このクエリを使用すると、必要な答えが得られます。

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 を使用しますが、これはあまりパフォーマンスが良くないと思いますが、この小さなデータセットでは機能します - もう少しデータを生成して様子を見ていきます。

于 2010-04-30T12:19:39.630 に答える