MySQL 获取考虑不同月份长度的月度发票记录
MySQL get records for monthly invoice taking different length of months into account
我有一个名为 subscriptions
的数据库 table。 table 中的每一行都有一个 created_at
日期,从这一天开始,每个月(之后)都必须为订阅开具发票。
因此 2017-05-29
,所有 created_at
天 == '29' 的订阅都必须开具发票,无论月份或年份。所以我想到了这个:
SELECT * FROM subscriptions WHERE DAY(created_at) = DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))
但在那种情况下,当上个月有 30 天时,我会遇到麻烦,因为在 30 日,它 returns 30,但在 31 日它也是 returns 30。所以所有订阅created_at
天 '30' 将开具两次发票。二月也会出问题。
另一个问题是反之,如果4月没有第31天,2017-03-31怎么开票
我可以在 PHP 中进行多次检查并检查当月是否已经开具发票等。但我想知道我是否可以通过 MySQL.
来解决这个问题
我根据上面的查询创建了一个 sqlfiddle 示例,其中有些日期会失败。
# Create subscription table
CREATE TABLE `subscription` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`company` varchar(100) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Fill subscription table
INSERT INTO `subscription` (`id`, `company`, `created_at`)
VALUES
(1, 'Acme', '2017-04-15 09:56:00'),
(2, 'Equmbo', '2017-02-28 10:00:00'),
(3, 'Megajo', '2017-03-31 08:10:34'),
(4, 'Astrotude', '2017-04-30 08:10:49');
# This is my base query for monthly invoice
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH));
# On 28th March, also fine
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-03-28', INTERVAL 1 MONTH));
# But on 29th March, Equmbo is invoice again
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-03-29', INTERVAL 1 MONTH));
# On 30st April, Astrotude AND Megajo must be invoiced. Only Astrotude returns.
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-04-30', INTERVAL 1 MONTH));
WHERE
/* don't invoice new subs from this month */
LAST_DAY(created_at)<LAST_DAY(CURDATE())
AND
(
/* exactly match sub's day value with today's day value */
DAY(created_at)=DAY(CURDATE())
OR
/* on last day of month, match sub's day if greater than today's day */
(CURDATE()=LAST_DAY(CURDATE()) AND DAY(created_at)>DAY(CURDATE()))
)
CURDATE() and LAST_DAY() return 一个完整的日期字符串 (yyyy-mm-dd)。
DAY() returns 一个整数(d 或 dd)。
我有一个名为 subscriptions
的数据库 table。 table 中的每一行都有一个 created_at
日期,从这一天开始,每个月(之后)都必须为订阅开具发票。
因此 2017-05-29
,所有 created_at
天 == '29' 的订阅都必须开具发票,无论月份或年份。所以我想到了这个:
SELECT * FROM subscriptions WHERE DAY(created_at) = DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH))
但在那种情况下,当上个月有 30 天时,我会遇到麻烦,因为在 30 日,它 returns 30,但在 31 日它也是 returns 30。所以所有订阅created_at
天 '30' 将开具两次发票。二月也会出问题。
另一个问题是反之,如果4月没有第31天,2017-03-31怎么开票
我可以在 PHP 中进行多次检查并检查当月是否已经开具发票等。但我想知道我是否可以通过 MySQL.
来解决这个问题我根据上面的查询创建了一个 sqlfiddle 示例,其中有些日期会失败。
# Create subscription table
CREATE TABLE `subscription` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`company` varchar(100) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Fill subscription table
INSERT INTO `subscription` (`id`, `company`, `created_at`)
VALUES
(1, 'Acme', '2017-04-15 09:56:00'),
(2, 'Equmbo', '2017-02-28 10:00:00'),
(3, 'Megajo', '2017-03-31 08:10:34'),
(4, 'Astrotude', '2017-04-30 08:10:49');
# This is my base query for monthly invoice
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH));
# On 28th March, also fine
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-03-28', INTERVAL 1 MONTH));
# But on 29th March, Equmbo is invoice again
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-03-29', INTERVAL 1 MONTH));
# On 30st April, Astrotude AND Megajo must be invoiced. Only Astrotude returns.
SELECT * FROM subscription WHERE DAY(created_at) = DAY(DATE_SUB('2017-04-30', INTERVAL 1 MONTH));
WHERE
/* don't invoice new subs from this month */
LAST_DAY(created_at)<LAST_DAY(CURDATE())
AND
(
/* exactly match sub's day value with today's day value */
DAY(created_at)=DAY(CURDATE())
OR
/* on last day of month, match sub's day if greater than today's day */
(CURDATE()=LAST_DAY(CURDATE()) AND DAY(created_at)>DAY(CURDATE()))
)
CURDATE() and LAST_DAY() return 一个完整的日期字符串 (yyyy-mm-dd)。
DAY() returns 一个整数(d 或 dd)。