年の各月のカレンダーイベントの数を数える

問題文:
年の各月のイベントの数を表示します。

各イベントには2つのフィールドがあります
-start_date-イベントの開始日
-end_date-イベント完了日

カレンダーイベントのラベル構造:
CREATE TABLE `events` (
`id` int (11) unsigned NOT NULL auto_increment,
`start_date` date default NULL ,
`end_date` date default NULL ,
`created` datetime default NULL ,
`modified` datetime default NULL ,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8


* This source code was highlighted with Source Code Highlighter .


期待される結果:
一月212月343月47
5月86月127月23
8月56九月1110月35
11月3412月24


可能なオプション:

-MONTH(開始日)= MONTH(終了日)、YEAR(開始日)= YEAR(終了日);
イベントは、1年の同じ月に開始および終了します。

-MONTH(開始日)<MONTH(終了日)、YEAR(開始日)= YEAR(終了日);
イベントは1か月で始まり、1年の別の月で終わります。

-MONTH(開始日)= MONTH(終了日)、YEAR(開始日)<YEAR(終了日);
イベントは、同じ月に開始されて終了しますが、異なる年になります(ちょうど1年続きます)。

-MONTH(開始日)<MONTH(終了日)、YEAR(開始日)<YEAR(終了日);
イベントは、異なる年の異なる月に始まり、終わります(12月に始まり、1月に終わります)。

解決策:
この問題を解決するには、2つの方法があります。値を行(各列は月)に表示するか、列(各行はイベント数のある月)に表示します。
JOINに苦しんだ後、結果を文字列に出力することにしました(JOINを使用する場合、イベントの無制限の期間が問題になりました)。 つまり、額の問題を解決し、年ごとにイベントを制限し、このイベントが発生する月を確認することにしました。 エントリを確認するために、MYSQL関数が作成されました。

実装:
DELIMITER $$

DROP FUNCTION IF EXISTS `isEventInMonth`$$

CREATE FUNCTION `isEventInMonth`(
startdate DATE ,
enddate DATE ,
_month INT (1),
_year INT (1)
) RETURNS INT (1)
BEGIN
DECLARE results INT (1);

IF YEAR (startdate) = YEAR (enddate) THEN
SET results = IF ( MONTH (startdate) = _month
AND MONTH (enddate) = _month
OR
( MONTH (startdate) <> MONTH (enddate)
AND ( MONTH (startdate) <= _month
AND MONTH (enddate) >= _month)
)
,1,0);
ELSEIF YEAR (startdate) = _year THEN
SET results = IF ( MONTH (startdate) <= _month ,1,0);
ELSE
SET results = IF ( MONTH (enddate) >= _month ,1,0);
END IF ;

RETURN results;
END $$

DELIMITER ;


* This source code was highlighted with Source Code Highlighter .


この入力関数は、イベントの開始日、イベントの終了日、確認が必要な月と年を受け取り、結果として0または1を返します。つまり、関数は現在の月がイベントの開始と終了の間隔にあるかどうかを確認します。

使用法:

SELECT
SUM (isEventInMonth(start_date,end_date,1,2011)) AS jan,
SUM (isEventInMonth(start_date,end_date,2,2011)) AS feb,
SUM (isEventInMonth(start_date,end_date,3,2011)) AS mar,
SUM (isEventInMonth(start_date,end_date,4,2011)) AS apr,
SUM (isEventInMonth(start_date,end_date,5,2011)) AS may,
SUM (isEventInMonth(start_date,end_date,6,2011)) AS jun,
SUM (isEventInMonth(start_date,end_date,7,2011)) AS jul,
SUM (isEventInMonth(start_date,end_date,8,2011)) AS aug,
SUM (isEventInMonth(start_date,end_date,9,2011)) AS sep,
SUM (isEventInMonth(start_date,end_date,10,2011)) AS 'oct' ,
SUM (isEventInMonth(start_date,end_date,11,2011)) AS nov,
SUM (isEventInMonth(start_date,end_date,12,2011)) AS 'dec'
FROM EVENTS WHERE YEAR (start_date) = 2011 OR YEAR (end_date) = 2011


* This source code was highlighted with Source Code Highlighter .


結果は行になり、各列には特定の年の月ごとのイベント数が表示されます。

要約すると:
実装はエレガントなふりをしません。誰かがイベントカレンダーなどの標準機能を実装すると便利だと思うでしょう。
質問や改善を歓迎します。
PS。 ラベルのタイトルと説明のフィールドを探してはいけません-これらは翻訳可能なフィールドであり、この表にはありません。

UPD:

ユーザーxtenderは、問題に対するより適切な解決策を提案しました。

SELECT <br>
sum ( CASE when t.`start_date`< '2010-02-01' and t.end_date>= '2010-01-01' then 1 else 0 end ) AS jan,<br>
sum ( CASE when t.`start_date`< '2010-03-01' and t.end_date>= '2010-02-01' then 1 else 0 end ) AS feb,<br>
sum ( CASE when t.`start_date`< '2010-04-01' and t.end_date>= '2010-03-01' then 1 else 0 end ) AS mar,<br>
sum ( CASE when t.`start_date`< '2010-05-01' and t.end_date>= '2010-04-01' then 1 else 0 end ) AS apr,<br>
sum ( CASE when t.`start_date`< '2010-06-01' and t.end_date>= '2010-05-01' then 1 else 0 end ) AS may,<br>
sum ( CASE when t.`start_date`< '2010-07-01' and t.end_date>= '2010-06-01' then 1 else 0 end ) AS jun,<br>
sum ( CASE when t.`start_date`< '2010-08-01' and t.end_date>= '2010-07-01' then 1 else 0 end ) AS jul,<br>
sum ( CASE when t.`start_date`< '2010-09-01' and t.end_date>= '2010-08-01' then 1 else 0 end ) AS aug,<br>
sum ( CASE when t.`start_date`< '2010-10-01' and t.end_date>= '2010-09-01' then 1 else 0 end ) AS sep,<br>
sum ( CASE when t.`start_date`< '2010-11-01' and t.end_date>= '2010-10-01' then 1 else 0 end ) AS oct,<br>
sum ( CASE when t.`start_date`< '2010-12-01' and t.end_date>= '2010-11-01' then 1 else 0 end ) AS nov,<br>
sum ( CASE when t.`start_date`< '2011-01-01' and t.end_date>= '2010-12-01' then 1 else 0 end ) AS dec <br>
FROM events t
<br>
<br>
* This source code was highlighted with Source Code Highlighter .

Source: https://habr.com/ru/post/J106793/


All Articles