0

いくつかの背景。相乗りアプリケーションに Rails 3 を使用しています。jquery カレンダー ライブラリとして fullcalendar を使用しています。特定の日に多くのイベントがある場合、うまく機能しませんだから、私がやりたいことは、2つの「イベントソース」を持つことです。1 つは、日付とカテゴリでグループ化された、カウントが特定の値よりも小さいすべてのイベントを返したいというものです。その他については、値よりも多くのカウントを持つすべてのレコードを返したいと考えています。

これが明確でない場合はお詫びします。いくつかのサンプルデータにより、より明確になる可能性があります

基本的なレコード構造:

|    id    |  date    |  category_id |
|    1     | 1-Aug    |       1      |
|    2     | 1-Aug    |       1      |
|    3     | 1-Aug    |       1      |
|    4     | 1-Aug    |       2      |
|    5     | 1-Aug    |       2      |
|    6     | 1-Aug    |       3      |

3 がマジック カウント数であると仮定すると (3 以上はグループ化する必要があります)、1 つの選択を返したいと思います

|    id    |  date    |  category_id |   count  |
|    1     | 1-Aug    |       1      |     3    |

(実際には、group_concat を使用して ID を (MYSQL と) 組み合わせることができるかどうかは気にしません)、私のユース ケースでは重要ではありません。知りたいのは、8 月 1 日にカテゴリ 1 に 3 つのエントリがあることです

2番目の選択は、他のすべてを返す必要があります

|    id    |  date    |  category_id |   count  |
|    4     | 1-Aug    |       2      |     2    |
|    5     | 1-Aug    |       2      |     2    |
|    6     | 1-Aug    |       3      |     1    |

返されるカウントは実際には必要ありませんが、ポイントは、カウント >= 3 を持たないすべての結果に個別の行があることです。

現在、私のSQLは次のようになっています。

SELECT `pools`.*
FROM       `pools`
INNER JOIN `fields`    ON `fields`.`id`    = `pools`.`field_id` 
INNER JOIN `regions`   ON `regions`.`id`   = `fields`.`region_id` 
INNER JOIN `countries` ON `countries`.`id` = `regions`.`country_id`
WHERE `regions`.`country_id` = 1
  AND `pools`.`confirmed`    = 1
  AND (leaving_date >= '2012-04-30 00:00:00')
  AND (leaving_date <= '2012-06-04 00:00:00')
GROUP BY field_id, leaving_date
HAVING   count(*) >= 3
ORDER BY leaving_date

返された配列を反復処理することもできますが、可能であれば SQL 側で実行したいと思います。また、データベーストリップの最小回数でそれを行いたいと思います..一般的なポインタは本当に高く評価されます!

4

1 に答える 1

0

多分これは始めるのに便利です:

CREATE TEMPORARY TABLE grouped_rows AS
  SELECT `pools`.*
  FROM       `pools`
  INNER JOIN `fields`     ON `fields`.`id`    = `pools`.`field_id` 
  INNER JOIN `regions`    ON `regions`.`id`   = `fields`.`region_id` 
  INNER JOIN `countries`  ON `countries`.`id` = `regions`.`country_id`
  WHERE `regions`.`country_id` = 1
    AND `pools`.`confirmed`    = 1
    AND (leaving_date >= '2012-04-30 00:00:00')
    AND (leaving_date <= '2012-06-04 00:00:00')
  GROUP BY field_id, leaving_date;
  HAVING   count(*) >= 3;


SELECT `pools`.*
FROM       `pools`
INNER JOIN `fields`     ON `fields`.`id`    = `pools`.`field_id` 
INNER JOIN `regions`    ON `regions`.`id`   = `fields`.`region_id` 
INNER JOIN `countries`  ON `countries`.`id` = `regions`.`country_id`
LEFT  JOIN grouped_rows ON grouped_rows.field_id     = pools.field_id
                       AND grouped_rows.leaving_date = pools.leaving_date
WHERE `regions`.`country_id` = 1
  AND `pools`.`confirmed`    = 1
  AND (leaving_date >= '2012-04-30 00:00:00')
  AND (leaving_date <= '2012-06-04 00:00:00')
  AND grouped_rows.some_not_null_field IS NULL

UNION ALL

SELECT * FROM grouped_rows

ORDER BY leaving_date;


DROP TEMPORARY TABLE grouped_rows;

UNION3 つのステートメントすべてを発行して、1 回の往復で結果を取得できるかどうかはわかりません。おそらく、temptable の select を の両方の半分に埋め込むことができますがUNION、MySQL サーバーにより多くの作業が必要になる場合があります (またはそうでない場合もあります)。

アップデート:

使用できる 1 つのクエリ ソリューションを見つけました。これは基本的なスケルトン構造にすぎませんが、それに応じてクエリを変換できると思います。

http://sqlfiddle.com/#!2/f67e3/18

SELECT
  IF( grouped.gcat, NULL, item.id ) AS out_id
 ,item.cat AS out_cat
 ,COALESCE( grouped.gcount, 1 ) out_count

FROM item

LEFT JOIN
(
  SELECT   count(*) AS gcount, cat AS gcat
  FROM     item
  GROUP BY gcat
  HAVING   count(*) >= 3
) AS grouped
  ON item.cat = grouped.gcat

GROUP BY out_id
于 2012-06-06T11:32:43.313 に答える