好的,所以我面对这个极其复杂的问题,因为我不是MySQL的大师,我肯定需要你的意见。
假设我们有一个数据库,使用下面的代码创建(我正在粘贴创建代码 - 只是绝对必要的表 - 以避免粘贴所有表):
DROP TABLE IF EXISTS `Jeweller`.`Orders`;
CREATE TABLE `Jeweller`.`Orders` (
`id` int(11) unsigned NOT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Product_categories`;
CREATE TABLE `Jeweller`.`Product_categories` (
`id` int(11) unsigned NOT NULL,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Product_orders`;
CREATE TABLE `Jeweller`.`Product_orders` (
`order_id` int(11) unsigned NOT NULL,
`product_id` int(11) unsigned NOT NULL,
`quantity` int(11),
`value` float,
FOREIGN KEY (`order_id`) REFERENCES `Jeweller`.`Orders`(`id`),
FOREIGN KEY (`product_id`) REFERENCES `Jeweller`.`Products`(`id`),
CHECK (`quantity`>0),
CHECK (`value`>0)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Product_returns`;
CREATE TABLE `Jeweller`.`Product_returns` (
`sale_id` int(11) unsigned NOT NULL,
`product_id` int(11) NOT NULL,
`date` date DEFAULT NULL,
`quantity` int(11),
`value` float,
FOREIGN KEY (`sale_id`) REFERENCES `Jeweller`.`Sales`(`id`),
FOREIGN KEY (`product_id`) REFERENCES `Jeweller`.`Products`(`id`),
CHECK (`quantity`>0),
CHECK (`value`>0)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Product_sales`;
CREATE TABLE `Jeweller`.`Product_sales` (
`sale_id` int(11) unsigned NOT NULL,
`product_id` int(11) NOT NULL,
`quantity` int(11),
`value` float,
FOREIGN KEY (`sale_id`) REFERENCES `Jeweller`.`Sales`(`id`),
FOREIGN KEY (`product_id`) REFERENCES `Jeweller`.`Products`(`id`),
CHECK (`quantity`>0),
CHECK (`value`>0)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Products`;
CREATE TABLE `Jeweller`.`Products` (
`id` int(11) unsigned NOT NULL,
`product_category_id` int(11) NOT NULL,
`seller_id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`description` text,
PRIMARY KEY (`id`),
FOREIGN KEY (`product_category_id`) REFERENCES `Jeweller`.`Product_categories`(`id`),
FOREIGN KEY (`seller_id`) REFERENCES `Jeweller`.`Sellers`(`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `Jeweller`.`Sales`;
CREATE TABLE `Jeweller`.`Sales` (
`id` int(11) unsigned NOT NULL,
`date` date DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
现在,我们将利润定义为:
Sales - Returns - Orders
您将如何查询要获取的内容:
按月和product_category获利,仅适用于2013年。
出于测试目的,这里是完整的DB Creation code以及DB Population code(带有一些演示数据)。 (SQLFiddle link)
P.S。
实际代码有点不同(以上只是一个例子 - 尽管是100%忠诚的代码)
经过多次尝试,我设法过滤了2013年的销售/订单/等等......我甚至设法按产品获得利润(虽然花了不少join
秒,{{ 1}} s等...(lol)...然而,这看起来要复杂得多。有什么想法吗?
答案 0 :(得分:1)
简单来说,如果重组是不可取的,那么我会做一个简单的查询来单独确定订单,退货和销售的价值,然后将它们加在一起。这可以使用UNION和子查询来完成,如以下示例所示:SQLFiddle
我也冒昧地将FLOAT交换为DECIMAL。索引等可能还有改进的余地,但这应该会让你在确定总和方面走得很好。如果查看子查询,您将看到ORDER和RETURN选择正在根据您的要求选择负值。
一个潜在的缺陷是,不会包含任何已删除产品记录的记录。通过将Product
连接更改为LEFT JOIN并适当地处理product_category_id的NULL值,可以避免这种情况。决定将此添加到最新示例中,但如果Product
中的行从未删除,则INNER JOIN就足够了
SELECT
d.thisMonth,
d.product_category_id,
SUM(d.sumValue)
FROM (
(
-- Get the order value
SELECT
'order' AS valueType,
MONTH(o.date) AS thisMonth,
p.product_category_id,
SUM(-po.value * po.quantity) AS sumValue
FROM Orders o
INNER JOIN Product_orders po
ON po.order_id = o.id
LEFT JOIN Products p
ON p.id = po.product_id
WHERE o.date BETWEEN '2013-01-01' AND '2013-12-31'
GROUP BY
thisMonth,
product_category_id
) UNION ALL (
-- Get the sales value
SELECT
'sale' AS valueType,
MONTH(s.date) AS thisMonth,
p.product_category_id,
SUM(ps.value * ps.quantity) AS sumValue
FROM Sales s
INNER JOIN Product_sales ps
ON ps.sale_id = s.id
INNER JOIN Products p
ON p.id = ps.product_id
WHERE s.date BETWEEN '2013-01-01' AND '2013-12-31'
GROUP BY
thisMonth,
product_category_id
) UNION ALL (
-- Get the return value
SELECT
'return' AS valueType,
p.product_category_id,
MONTH(pr.date) AS thisMonth,
SUM(-pr.value * pr.quantity) AS sumValue
FROM Product_returns pr
INNER JOIN Products p
ON p.id = pr.product_id
WHERE pr.date BETWEEN '2013-01-01' AND '2013-12-31'
GROUP BY
thisMonth,
product_category_id
)
) d
GROUP BY
d.thisMonth,
d.product_category_id;
答案 1 :(得分:1)
以下是您的架构的近似值......
DROP TABLE IF EXISTS orders;
CREATE TABLE orders
( order_id int(11) unsigned NOT NULL auto_increment
, date date DEFAULT NULL
, PRIMARY KEY (order_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO orders VALUES
(NULL,'2013-01-01'),
(NULL,'2013-01-01'),
(NULL,'2013-02-02'),
(NULL,'2013-02-03'),
(NULL,'2013-03-05'),
(NULL,'2013-06-07');
DROP TABLE IF EXISTS product_orders;
CREATE TABLE product_orders
( order_id int unsigned NOT NULL
, product_id int unsigned NOT NULL
, quantity int NOT NULL DEFAULT 1
, value DECIMAL(5,2)
, PRIMARY KEY(order_id,product_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO product_orders VALUES
(1,101,1,100),
(1,102,1,50),
(2,101,2,200),
(3,101,1,100),
(4,102,2,100),
(4,103,3,150),
(5,104,1,300),
(6,102,1,50),
(6,103,2,100),
(6,104,1,300);
DROP TABLE IF EXISTS product_returns;
CREATE TABLE product_returns
( sale_id int unsigned NOT NULL
, product_id int NOT NULL
, date date DEFAULT NULL
, quantity int NOT NULL DEFAULT 1
, value DECIMAL(5,2)
, PRIMARY KEY(sale_id,product_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO product_returns VALUES
(21,101,'2013-01-04',2,200),
(22,102,'2013-03-06',1,50),
(22,103,'2013-05-08',1,50),
(23,104,'2013-06-09',1,300);
DROP TABLE IF EXISTS product_sales;
CREATE TABLE product_sales
( sale_id int unsigned NOT NULL
, product_id int NOT NULL
, quantity int NOT NULL
, value DECIMAL(5,2)
, PRIMARY KEY(sale_id,product_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO product_sales VALUES
(20,101,1,100),
(20,102,1,50),
(21,101,3,300),
(22,101,1,100),
(22,102,2,100),
(22,103,1,50),
(23,103,2,100),
(23,104,2,600);
DROP TABLE IF EXISTS products;
CREATE TABLE products
( product_id int unsigned NOT NULL AUTO_INCREMENT
, product_category_id int NOT NULL
, name varchar(100) NOT NULL
, description text NULL
, PRIMARY KEY (product_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO products VALUES
(101,1,'donuts','Mmm, donuts'),
(102,2,'buzz Cola','Mmm, donuts'),
(103,2,'duff beer','Can\'t get enough'),
(104,1,'Krusty-O\'s','Yum, yum');
DROP TABLE IF EXISTS sales;
CREATE TABLE sales
( sale_id int NOT NULL
, date date DEFAULT NULL
, PRIMARY KEY (sale_id)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO sales VALUES
(20,'2013-01-12'),
(21,'2013-02-15'),
(22,'2013-03-17'),
(23,'2013-05-18');
...以及可能的查询...
SELECT p.product_category_id
, MONTH(date) month
, SUM(value) profit
FROM
( SELECT product_id,value, date
FROM product_sales ps
JOIN sales s
ON s.sale_id = ps.sale_id
UNION ALL
SELECT product_id,value*-1,date FROM product_returns
UNION ALL
SELECT product_id,value*-1,date
FROM product_orders po
JOIN orders o
ON o.order_id = po.order_id
) x
JOIN products p
ON p.product_id = x.product_id
WHERE YEAR(date) = 2013
GROUP
BY p.product_category_id
, MONTH(date);
+---------------------+-------+---------+
| product_category_id | month | profit |
+---------------------+-------+---------+
| 1 | 1 | -400.00 |
| 1 | 2 | 200.00 |
| 1 | 3 | -200.00 |
| 1 | 5 | 600.00 |
| 1 | 6 | -600.00 |
| 2 | 1 | 0.00 |
| 2 | 2 | -250.00 |
| 2 | 3 | 100.00 |
| 2 | 5 | 50.00 |
| 2 | 6 | -150.00 |
+---------------------+-------+---------+
......和一个相同的方形:http://www.sqlfiddle.com/#!2/22a1d/1