2017-05-29 8 views
1

私はsubscriptionsというデータベーステーブルを持っています。表の各行には、created_atの日付があります。この日以降、毎月(その後)、サブスクリプションを請求する必要があります。MySQLは、毎月の異なる月数を考慮した毎月の請求書のレコードを取得します

したがって、には、created_at日== '29'のすべてのサブスクリプションが、月または年に関係なく請求されなければなりません。だから私はこの考え:

SELECT * FROM subscriptions WHERE DAY(created_at) = DAY(DATE_SUB(CURDATE(), INTERVAL 1 MONTH)) 

しかし、前月30日がある場合30日に、それは30を返しますが、31日に、それはまた、30だから、すべてのサブスクリプションを返すので、その場合には、私は、トラブルに巻き込まれますcreated_at日の '30'は2回請求されます。また、2月に問題を提起する予定です。

もう1つの問題は、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)); 
+1

次のようになります。LAST_DAY()= CURDATE()は今日の数値よりも日の値が大きいすべての日付を対象としていますか? ...私は答えに変えることができるかどうかを知るだろう(誰かがそれに私を打たない限り)。 – mickmackusa

+0

@mickmackusa、私はあなたがどこに行くのか見ていますが、私はまだそれを行う方法を知らない! – Timo002

+0

https://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-クエリ – Strawberry

答えて

2
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()LAST_DAY()完全な日付文字列(YYYY-MM-DD)を返します。

DAY()は整数(dまたはdd)を返します。

+0

これは本当に素晴らしいです!最後の部分が最も難しいです、私はそれを理解できませんでした! – Timo002

+1

@ Timo002私は小さな修正/洗練を加える必要がありました。最終条件で '> ='をチェックする必要はありません。 'OR'より前の' DAY()= DAY() 'はすでに' = 'をチェックしています。 'OR'の後に' = 'をもう一度チェックする点はありません。私は自分の答えを更新しました。あなたのプロジェクトでこの微調整を行うことをお勧めします。 – mickmackusa

関連する問題