0

一些背景。我将 Rails 3 用于拼车应用程序。我使用 fullcalendar 作为 jquery 日历库。当某一天有很多事件时,它就不会很好地工作所以,我想做的是拥有两个“事件源”。一方面,我想返回计数小于某个值的所有事件,按日期和类别分组。对于其他,我想返回所有计数超过值的记录

抱歉,如果不清楚,一些示例数据可能会使其更明显

基本记录结构:

|    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 或更高)我想要一个选择返回

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

(我实际上并不关心 ID 可以使用 group_concat 组合(与 MYSQL)),在我的用例中它并不重要 - 我想知道的是,8 月 1 日类别 1 有 3 个条目

第二个选择应该返回其他所有内容

|    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;

我不知道您是否可以发出所有三个语句并获得UNION一次往返的结果。也许您可以将 temptable 的 select 嵌入到UNION.

更新:

我找到了一个可以使用的单查询解决方案。这只是基本的骨架结构,但我认为您可以根据它转换您的查询:

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 回答