Mysql 更改数据库模式或查询以返回给定时间段内的余额
我提出了以下模式:Mysql 更改数据库模式或查询以返回给定时间段内的余额,mysql,sql,Mysql,Sql,我提出了以下模式: CREATE TABLE products ( id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, quantity INT(10) UNSIGNED NOT NULL, purchase_price DECIMAL(8,2) NOT NULL, sell_price DECIMAL(8,2) NOT NULL, provide
CREATE TABLE products
(
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
quantity INT(10) UNSIGNED NOT NULL,
purchase_price DECIMAL(8,2) NOT NULL,
sell_price DECIMAL(8,2) NOT NULL,
provider VARCHAR(255) NULL,
created_at TIMESTAMP NULL,
PRIMARY KEY (id)
);
# payment methods = {
# "0": "CASH",
# "1": "CREDIT CARD",
# ...
# }
CREATE TABLE orders
(
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
product_id INT(10) UNSIGNED NOT NULL,
quantity INT(10) UNSIGNED NOT NULL,
payment_method INT(11) NOT NULL DEFAULT 0,
created_at TIMESTAMP NULL,
PRIMARY KEY (id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
# status = {
# "0": "PENDING"
# "1": "PAID"
# }
CREATE TABLE invoices
(
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
price INT(10) UNSIGNED NOT NULL,
status INT(10) UNSIGNED NOT NULL DEFAULT 0,
created_at TIMESTAMP NULL,
PRIMARY KEY (id)
);
# payment methods = {
# "0": 'CASH',
# "1": 'CREDIT CARD',
# ...
# }
CREATE TABLE bills
(
id INT(10) UNSIGNED AUTO_INCREMENT NOT NULL,
name VARCHAR(255) NOT NULL,
payment_method INT(10) UNSIGNED NOT NULL DEFAULT 0,
price DECIMAL(8,2) NOT NULL,
created_at TIMESTAMP NULL,
PRIMARY KEY (id)
);
和以下查询以选择余额:
SELECT ((orders + invoices) - bills) as balance
FROM
(
SELECT SUM(p.sell_price * o.quantity) as orders
FROM orders o
JOIN products p
ON o.product_id = p.id
) orders,
(
SELECT SUM(price) as invoices
FROM invoices
WHERE status = 1
) invoices,
(
SELECT SUM(price) as bills
FROM bills
) bills;
它可以正常工作并返回正确的余额,但我想使用Morris.js创建一个图表,我需要将其更改为在给定时间段以以下格式返回每日或每月余额:
每日2017-02-27至2017-03-01
balance | created_at
--------------------------
600.00 | 2017-03-01
50.00 | 2017-02-28
450.00 | 2017-02-27
2017-01年至2017-03年每月
balance | created_at
--------------------------
200.00 | 2017-03
250.00 | 2017-02
350.00 | 2017-01
我需要在模式或查询中更改什么才能以这种方式返回结果
欢迎任何提示。提前感谢在选择列表中包含创建日期,并在每个查询中包含GROUP BY子句
放弃用于联接操作的老式逗号运算符,并将其替换为左联接
要返回没有订单、没有付款或没有发票的日期,我们需要一个保证返回日期值的单独行源。例如,我们可以使用内联视图:
SELECT d.created_dt
FROM ( SELECT '2017-02-27' + INTERVAL 0 DAY AS created_dt
UNION ALL SELECT '2017-02-28'
UNION ALL SELECT '2017-03-01'
) d
ORDER BY d.created_dt
内联视图只是一个选项。如果我们有一个日历表,其中包含我们感兴趣的三个日期的行,那么我们可以使用它。重要的是,我们有一个查询,它保证返回到我们想要返回的具有不同created_at date值的整整三行
一旦我们有了它,我们就可以添加一个左连接来获取该日期的账单价值
SELECT d.created_dt
, b.bills
FROM ( SELECT '2017-02-27' + INTERVAL 0 DAY AS created_dt
UNION ALL SELECT '2017-02-28'
UNION ALL SELECT '2017-03-01'
) d
LEFT
JOIN ( SELECT DATE(bills.created_at) AS created_dt
, SUM(bills.price) AS bills
FROM bills
WHERE bills.created_at >= '2017-02-27'
AND bills.created_at < '2017-03-01' + INTERVAL 1 DAY
GROUP BY DATE(bills.created_at)
) b
ON b.created_dt = d.created_dt
ORDER BY d.created_dt
为了每月获得结果,我们需要一个每月返回一行的日历查询。让我们假设我们将返回一个日期值,该值作为一个月的第一天。例如:
SELECT d.created_dt
, IFNULL(i.invoices,0) AS invoices
, COALESCE(b.bills,0) AS bills
FROM ...
SELECT d.created_month
FROM ( SELECT '2017-02-01' + INTERVAL 0 DAY AS created_month
UNION ALL SELECT '2017-03-01'
) d
ORDER BY d.created_month
内联视图查询需要按创建的月份分组,因此它们为每个月份值返回一个值。我的首选是使用DATE_FORMAT函数返回月份的第一天,该天是从created_at派生的。但还有其他方法可以做到这一点。目标是为“2017-02-01”返回单行,为“2017-03-01”返回单行。请注意,创建时的日期范围从“2017-02-01”延伸至“2017-04-01”,但不包括“2017-04-01”,因此我们得到了整个月的总数
( SELECT DATE_FORMAT(bills.created_at,'%Y-%m-01') AS created_month
, SUM(bills.price) AS bills
FROM bills
WHERE bills.created_at >= '2017-02-01'
AND bills.created_at < '2017-03-01' + INTERVAL 1 MONTH
GROUP BY DATE_FORMAT(bills.created_at,'%Y-%m-01')
) b
哇!感谢@spencer7593提供了极其详细的答案!只是好奇:这张日历表只能放日期?如果是这样的话,它将需要通过一个预定的过程填充每个未来的日期。这是一种常见的做法吗?我不知道有日历表是否常见。对于其他数据库,很容易生成日期列表、Oracle recursive CONNECT BY inline view、SQL Server recursive CTE等。MySQL中没有简单的工具,因此我们创建了一个表cal dt DATE NOT NULL PRIMARY KEY ENGINE=InnoDB,并插入了满足我们要求的连续行范围。2001年1月1日至2037年12月31日。
( SELECT DATE_FORMAT(bills.created_at,'%Y-%m-01') AS created_month
, SUM(bills.price) AS bills
FROM bills
WHERE bills.created_at >= '2017-02-01'
AND bills.created_at < '2017-03-01' + INTERVAL 1 MONTH
GROUP BY DATE_FORMAT(bills.created_at,'%Y-%m-01')
) b