2

指定された期間内の1日の予定をカウントするmysqlステートメントに問題があります。開始列と終了列を含むカレンダーテーブルがあります(タイプ= DateTime)。次のステートメントは、全体的な予定を含む11月のすべての予定をカウントする必要があります。

SELECT 
    COUNT('APPOINTMENTS') AS Count, 
    DATE(c.StartingDate) AS Datum 
FROM t_calendar c
    WHERE 
        c.GUID = 'blalblabla' AND
        ((DATE(c.StartingDate) <= DATE('2012-11-01 00:00:00')) AND (DATE(c.EndingDate) >= DATE('2012-11-30 23:59:59'))) OR
        ((DATE(c.StartingDate) >= DATE('2012-11-01 00:00:00')) AND (DATE(c.EndingDate) <= DATE('2012-11-30 23:59:59')))
    GROUP BY DATE(c.StartingDate)
    HAVING Count > 1

しかし、StartingDateの前に開始し、StartingDateで終了する予定を含めるにはどうすればよいですか?

例えば

  • StartedDate = 2012-11-14 17:00:00、EndingDate = 2012-11-15 08:00:00
  • StartedDate = 2012-11-15 09:00:00、EndingDate = 2012-11-15 10:00:00
  • StartedDate = 2012-11-15 11:00:00、EndingDate = 2012-11-15 12:00:00

私のステートメントは、11月15日のカウント2を返します。しかし、最初の予定が欠落しているため、それは間違っています。これらの予定を含める方法は?私が欠けているもの、UNION SELECT、JOIN、サブ選択?


考えられる解決策は?

SELECT 
    c1.GUID, COUNT('APPOINTMENTS') + COUNT(DISTINCT c2.ANYFIELD) AS Count, 
    DATE(c1.StartingDate) AS Datum,
    COUNT(DISTINCT c2.ANYFIELD)
FROM 
    t_calendar c1
LEFT JOIN
    t_calendar c2
        ON
            c2.ResourceGUID = c1.ResourceGUID AND
            (DATE(c2.EndingDate) = DATE(c1.StartingDate)) AND 
            (DATE(c2.StartingDate) < DATE(c1.StartingDate))
WHERE 
    ((DATE(c1.StartingDate) <= DATE('2012-11-01 00:00:00')) AND (DATE(c1.EndingDate) >= DATE('2012-11-30 23:59:59'))) OR
    ((DATE(c1.StartingDate) >= DATE('2012-11-01 00:00:00')) AND (DATE(c1.EndingDate) <= DATE('2012-11-30 23:59:59')))    
GROUP BY 
    c1.ResourceGUID,
    DATE(c1.StartingDate)
4

1 に答える 1

4

最初:範囲チェックを統合します

まず、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を作成しました。これが何をするかです...

Num0から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

今あなたがしなければならないことは

  1. 表から数値を選択して日付の範囲を選択し、Numそれらを日付に変換します。
  2. 次に、それらの日付に予定を参加させて、特定の日に該当する予定がその特定の日に参加するようにします。
  3. 次に、これらすべての予定を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 |
于 2012-11-14T10:00:22.760 に答える