最初:範囲チェックを統合します
まず、2つの範囲where
条件を1つの範囲条件に置き換えることができます。また、ターゲットの日付範囲と完全に重複しているか、完全に含まれている予定のみをカウントしているようです。部分的に重なっているものは含まれません。したがって、範囲の開始日に終了する予定についての質問。
句をwhere
わかりやすくするために、次のように簡略化します。
- ターゲット範囲を定義する2つの変数:
rangeStart
(あなたの場合、2012年11月1日)
rangeEnd
(2012年12月1日00:00:00.00000と仮定します)
datetime
(関数を使用して)行った方法で日付のみに変換することはありませんがdate
、簡単に行うことができます。
これらを念頭に置いて、where
条項を大幅に簡略化し、特定の範囲のすべての予定をカバーすることができます。
...
where (c.StartingDate < rangeEnd) and (c.EndingDate >= rangeStart)
...
これにより、ターゲット範囲内にあるすべての予定が検索され、これらすべての予定のケースがカバーされます。
start end
target range |==============|
partial front |---------|
partial back |---------|
total overlap |---------------------|
total containment |-----|
部分的な前面/背面も、ターゲット範囲(あなたが求めていたもの)にほとんど触れない場合があります。
2番目:問題の解決
なぜ最初のレコードが欠落しているのですか?特定の日に開始する予定が複数having
あるグループのみを収集するという条項があるため、 11月15日には2つありますが、14日には1つしかないため、ではないため除外されます。Count = 1
> 1
2番目の質問に答えるには、私が欠けているのは次のとおりです。何も欠けていません。実際には、ステートメントが多すぎて、単純化する必要があります。
代わりに、次のステートメントを試してください。これにより、目的のステートメントが正確に返されます。
select count(c.GUID) as Count,
date(c.StartingDate) as Datum
from t_calendar c
where (c.GUID = 'blabla') and
(c.StartingDate < str_to_date('2012-12-01', '%Y-%m-%d') and
(c.EndingDate >= str_to_date('2012-11-01', '%Y-%m-%d'))
group by date(c.StartingDate)
関数を使用str_to_date
して、文字列から日付への変換をより安全にしました。
本当に必要ではないので、なぜあなたhaving
があなたの声明に含めたのかよくわかりません。実際のステートメントがより複雑で、最も関連性の高い部分のみを含めた場合を除きます。その場合、次のように変更する必要があります。
having Count > 0
任意の日付範囲での1日あたりの予約数の取得
他の方法も考えられますが、最も一般的な方法は、数値または?calendar *テーブルを使用して、範囲を個々のポイント(日数)に分割する機能を提供することです。彼らはあなたがこの数字の表にあなたの予定を参加させて結果を提供しなければなりません。
私はそのトリックを行うSQLFiddleを作成しました。これが何をするかです...
Num
0からxまでの数値を持つ数値テーブルがあるとします。Cal
そして、あなたの記録を含む予定表。次のスクリプトは、これら2つのテーブルを作成し、いくつかのデータを入力します。数は100までで、3か月分のデータには十分です。
-- appointments
create table Cal (
Id int not null auto_increment primary key,
StartDate datetime not null,
EndDate datetime not null
);
-- create appointments
insert Cal (StartDate, EndDate)
values
('2012-10-15 08:00:00', '2012-10-20 16:00:00'),
('2012-10-25 08:00:00', '2012-11-01 03:00:00'),
('2012-11-01 12:00:00', '2012-11-01 15:00:00'),
('2012-11-15 10:00:00', '2012-11-16 10:00:00'),
('2012-11-20 08:00:00', '2012-11-30 08:00:00'),
('2012-11-30 22:00:00', '2012-12-05 00:00:00'),
('2012-12-01 05:00:00', '2012-12-10 12:00:00');
-- numbers table
create table Nums (
Id int not null primary key
);
-- add 100 numbers
insert into Nums
select a.a + (10 * b.a)
from (select 0 as 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 a,
(select 0 as 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 b
今あなたがしなければならないことは
- 表から数値を選択して日付の範囲を選択し、
Num
それらを日付に変換します。
- 次に、それらの日付に予定を参加させて、特定の日に該当する予定がその特定の日に参加するようにします。
- 次に、これらすべての予定を1日ごとにグループ化して、結果を取得します
これを行うコードは次のとおりです。
-- just in case so comparisons don't trip over
set names 'latin1' collate latin1_general_ci;
-- start and end target date range
set @s := str_to_date('2012-11-01', '%Y-%m-%d');
set @e := str_to_date('2012-12-01', '%Y-%m-%d');
-- get appointment count per day within target range of days
select adddate(@s, n.Id) as Day, count(c.Id) as Appointments
from Nums n
left join Cal c
on ((date(c.StartDate) <= adddate(@s, n.Id)) and (date(c.EndDate) >= adddate(@s, n.Id)))
where adddate(@s, n.Id) < @e
group by Day;
そして、これはこのかなり単純なselectステートメントの結果です。
| DAY | APPOINTMENTS |
-----------------------------
| 2012-11-01 | 2 |
| 2012-11-02 | 0 |
| 2012-11-03 | 0 |
| 2012-11-04 | 0 |
| 2012-11-05 | 0 |
| 2012-11-06 | 0 |
| 2012-11-07 | 0 |
| 2012-11-08 | 0 |
| 2012-11-09 | 0 |
| 2012-11-10 | 0 |
| 2012-11-11 | 0 |
| 2012-11-12 | 0 |
| 2012-11-13 | 0 |
| 2012-11-14 | 0 |
| 2012-11-15 | 1 |
| 2012-11-16 | 1 |
| 2012-11-17 | 0 |
| 2012-11-18 | 0 |
| 2012-11-19 | 0 |
| 2012-11-20 | 1 |
| 2012-11-21 | 1 |
| 2012-11-22 | 1 |
| 2012-11-23 | 1 |
| 2012-11-24 | 1 |
| 2012-11-25 | 1 |
| 2012-11-26 | 1 |
| 2012-11-27 | 1 |
| 2012-11-28 | 1 |
| 2012-11-29 | 1 |
| 2012-11-30 | 2 |