2016-03-25 10 views
1

で販売日数残りの計算:MySQLの:私は毎月の収入の目標を達成するために、毎日獲得する必要があるどのくらいの収入を述べ、毎日の収入の目標計算を持っ月

'Revenue_Goal'/'Selling_Days' 

(注:「Selling_Days」は私が達成しようとしているのは、何日が経過したかに基づいて調整された1日の目標を得ることです。私はこれを部分的に達成しました:

しかし、私が理解できない部分は調整された公式での販売日の計算だけです。私は、上記の式(または類似したもの)のみをカウントを使用する必要がある日とき:

  • 月曜〜金曜= 1販売日
  • 土曜日= 0.5の販売日
  • 日曜日= 0

したがって、今日が3/25/16の場合、私のDATEDIFF計算は6を返しますが、私の目標は4.5を返すことです。

ご協力いただきましてありがとうございます。

+1

テーブルの構造は何ですか? DateのMAXを取得すると、その列には何がありますか?すでにDBに何かがあるようですが、あなたがすでに持っているものを知ることは重要です。私は銀行の休暇の問題も持っていると思います... –

+0

「日付」は収入が得られた日です。 MAX( 'Date')は、2016年3月31日を返します。 – czmudzin

+0

テーブルに格納されているデータと何が関係しているのかよくわかりません。 – Strawberry

答えて

1

をカルクするn個の方法のこの1つはそれが保存された機能としてこれを書くために理にかなっています。私は3つの方法を考えることができますが、それぞれ前のものに改善しています(方法2はおそらく十分です)。

方法1:最初の日付から開始し、2番目の日付まで増分します。日付ごとに、DAYOFWEEK()を呼び出します。

select count_days_goal(DATE('2016-03-21'), DATE('2016-03-27')); 
select count_days_goal(DATE('2016-03-01'), DATE('2016-03-27')); 

これは簡単です:土曜日は、0.5を追加した場合日曜日は、その後0を、追加した場合はそれ以外の場合は1

DROP FUNCTION IF EXISTS `count_days_goal`; 

DELIMITER $$ 
CREATE FUNCTION `count_days_goal`(start_date DATE, end_date DATE) RETURNS FLOAT 
    DETERMINISTIC 
BEGIN 
    DECLARE sell_days FLOAT; 
    DECLARE dow INT; 

    SET sell_days = 0.0; 
    WHILE start_date <= end_date DO 
     SET dow = DAYOFWEEK(start_date); 
     IF (dow > 1) THEN 
      IF (dow = 7) THEN SET sell_days = sell_days + 0.5; 
      ELSE SET sell_days = sell_days + 1.0; 
      END IF; 
     END IF; 
     SET start_date = start_date + INTERVAL 1 DAY; 
    END WHILE; 

    RETURN (sell_days); 
END$$ 
DELIMITER ; 

カップルのテストは、(私の実装は数え日の最後の日が含まれていることに注意してください)を追加それは非効率です。日々離れていくほど時間がかかります。 1つのコールはまだ目の瞬きより速いですが、ほとんどの開発者にとってはやや不快です。幸いにも私たちはより良いことができます。

方法2:各週は5.5営業日です。ですから、日付の間の日数を7で割り、残りは無視し、5.5で複数を除いてください。

例:32日は(4週間+4日)です。これは22営業日に4つの余りを加えたものです。

残っているのは物事が面倒なところです。それらの4日間は土曜日を含むかもしれない、またはそうでないかもしれない。最も簡単な解決策は、最後の数日間方法1を使用することです。 6日以上はループしないので、高速です。

だから今のコードは次のようになります。

DROP FUNCTION IF EXISTS `count_days_goal`; 
DELIMITER $$ 
CREATE FUNCTION `count_days_goal`(start_date DATE, end_date DATE) RETURNS FLOAT 
    DETERMINISTIC 
BEGIN 
    DECLARE sell_days FLOAT; 
    DECLARE dow INT; 
    DECLARE whole_weeks INT; 

    SET whole_weeks = FLOOR(DATEDIFF(end_date, start_date)/7); 
    SET start_date = start_date + (7 * whole_weeks); 
    SET sell_days = whole_weeks * 5.5; 

    WHILE start_date <= end_date DO 
     SET dow = DAYOFWEEK(start_date); 
     IF (dow > 1) THEN 
      IF (dow = 7) THEN SET sell_days = sell_days + 0.5; 
      ELSE SET sell_days = sell_days + 1.0; 
      END IF; 
     END IF; 
     SET start_date = start_date + INTERVAL 1 DAY; 
    END WHILE; 

    RETURN (sell_days); 
END$$ 
DELIMITER ; 

方法3:あなたはまた、完全に方法2を使用しますが、ループを取り除くことができます。それがどのように行われるかを見るには、あなたの前にカレンダーを置くことが役立ちます。 (私はこれを実装するのは苦労しませんでした;方法2はかなり良いです。)

ループの代わりに、最初と最後の日にDAYOFWEEKを呼び出します。それらをdow_startdow_endと呼ぶことにしましょう。

dow_start < dow_endの場合、これらの厄介な残りの日はすべて週内にあるため、土曜日から日曜日に折り返されません。だから、すべてを行う必要がある:それらの厄介な残り日数がラップアラウンドん

SET answer = DATEDIFF(dow_end, dow_start) + 1; 
IF dow_start = 1 (i.e. Sunday) THEN subtract 1 from answer 
IF dow_end is 7 (i.e. Saturday) THEN subtract 0.5 from answer 

その後、dow_start > dow_end場合。その場合、dow_startdow_endを交換することができます(前のケースに戻ります)。前回と同じように計算しますが、5.5から答えを減算して1を加算します。(説明:day_startday_endの間にない曜日を数えてから、週の合計から減算します)

それを書いたりテストしたりしないでください。完全に正しいとは限りません。

銀行休暇の処理方法:テーブル内にある場合は、単にCOUNTの2つの日付間の行数を使用できます。あなたの答えからそれを引きます。簡単! (銀行休暇は決して週末にはないと仮定します)さまざまな国の銀行休業日をリストするWebサイトもあります。休日テーブルを簡単に作成できるように、今後の予定リストを生成するものもあります。

+0

方法1について詳しく説明できますか?私は実際にこれらの計算とデータセットを使用するのはちょうど私の(初心者のMySQLユーザーとして)ため、それは迅速かつ汚れた何かを探しています。 – czmudzin

+0

確かに、喜んで助けてください。最初の2つのメソッドをストアド関数として書きました。 – Bampfer

2

この

SELECT 
    SUM( 
    ELT(DAYOFWEEK(CONCAT(DATE_FORMAT(now(), '%Y-%m-'),nr)), 
    '0','1','1','1','1','1','0.5')) calc_days 
FROM (
SELECT d2.a*10+d1.a AS nr FROM (
    SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 
    UNION ALL SELECT 
    5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS d1 
    CROSS JOIN (
    SELECT 0 a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) AS d2 
) AS x 
WHERE nr BETWEEN DAY(NOW()) AND DAY(LAST_DAY(NOW())) 
ORDER BY nr; 
関連する問題