根据 CakePHP / MySQL 中的大量 HABTM 条件计算每个城市的总事件数

发布于 2024-11-19 20:49:00 字数 1634 浏览 5 评论 0原文

在我的“事件列表”页面上,我列出了现在或以后发生的所有事件。

然后,用户可以选择他们想要查询的城市、事件类型、事件子类型等,以仅返回与其所选项目匹配的事件。

我的这个工作得很好 - 我正在根据他们的输入构建我的连接/条件...等,并且它返回带有分页的正确事件...等。

现在的问题是 - 我在页面左侧有一个城市列表,并且想要这些城市中的事件数量(与类型、子类型等相同) - 即:

New York (16)
Chicago (15)
Austin (8)
...

Sports (6)
  - Baseball (2)
  - Basketball (2)
  - Football (0)
Outdoors (5)
...

这不会是一个大的交易除了我使用联接来获取我需要的数据外,所以当我尝试这样做时:

SELECT COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total,
`VenueCity`.`name`, `VenueCity`.`id`, `VenueCity`.`slug`, `RestaurantCity`.`name`,
`RestaurantCity`.`id`, `RestaurantCity`.`slug` FROM `events` AS `Event`
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`)
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`)
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`)
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`)
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)
WHERE `Event`.`name` IS NOT NULL
AND `Event`.`approval_status_id` = 1
AND `Date`.`start` >= '2011-07-12 16:45:39'
GROUP BY `VenueCity`.`id`
ORDER BY `total` DESC 

它返回每个存在的日期的计数(即 - 如果有 10 个事件,每个事件有 5 个日期,它将显示 50 作为数数)。

更不用说,在为 Cake 的分页运行两次之后,我必须再次运行这个复杂的查询。我假设如果我继续走这条路,我也必须对每种类型、子类型和子子类型再次执行此操作。

TLDR:

我有一个复杂的多连接查询,它根据事件计划->日期获取事件。我还需要能够告诉(无论是在同一个查询中还是在新的查询中)每个城市、类型、子类型等发生了多少事件。

我祈祷答案是“哦,这很简单,你可以做 __” - 但会接受你的任何建议/帮助。

On my "Event Listings" page, I list all the events that are happening NOW or later.

The user can then select which city(s), event type(s), event sub type(s)...etc they want to query against to return only events that match their selected item(s).

I have this working just fine - I'm building my joins/conditions... etc based on their input, and it's returning the correct events w/ pagination..etc.

The problem now is - I have a list of cities on the left of the page, and want to have the number of events in those cities (same with type, sub type..etc) - ie:

New York (16)
Chicago (15)
Austin (8)
...

Sports (6)
  - Baseball (2)
  - Basketball (2)
  - Football (0)
Outdoors (5)
...

It wouldn't be a big deal except that I'm using joins to get the data I need, so when I try this:

SELECT COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total,
`VenueCity`.`name`, `VenueCity`.`id`, `VenueCity`.`slug`, `RestaurantCity`.`name`,
`RestaurantCity`.`id`, `RestaurantCity`.`slug` FROM `events` AS `Event`
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`)
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`)
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`)
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`)
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)
WHERE `Event`.`name` IS NOT NULL
AND `Event`.`approval_status_id` = 1
AND `Date`.`start` >= '2011-07-12 16:45:39'
GROUP BY `VenueCity`.`id`
ORDER BY `total` DESC 

It's returning the count for EVERY date that exists (ie - if there are 10 events, each having 5 dates, it would show 50 as the count).

Not to mention, I'm having to run this complicated query AGAIN, after already running it twice for Cake's pagination. And I assume if I keep down this path, I'll have to do it again for every type, sub type, and sub sub type as well.

TLDR:

I have a complicated, mult-join query that gets events based on Event-Schedule->Date. I need to also be able to tell (whether in the same query or a new one(s)) how many events are happening for each city, type, sub type...etc etc.

I'm crossing my fingers the answer is "oh, that's easy, you can just do __" - but will take any advice/help you have.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

做个少女永远怀春 2024-11-26 20:49:01

尝试在时间表表上进行子查询,类似这样的操作将为每个事件提供一个随机日期(很可能是在表中输入的第一个日期)。可能需要一些调试,但这应该可以帮助您...


SELECT COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total,
`VenueCity`.`name`, `VenueCity`.`id`, `VenueCity`.`slug`, `RestaurantCity`.`name`,
`RestaurantCity`.`id`, `RestaurantCity`.`slug` FROM `events` AS `Event`
INNER JOIN 

(SELECT MIN(subSchedule.`id`) AS `id`,subSchedule.`event_id` 
   FROM `schedules` AS subSchedule
   INNER JOIN dates AS subDate ON (subDate.`schedule_id` = subSchedule.`id`)   
   WHERE `subDate`.`start` >= '2011-07-12 16:45:39'
   GROUP BY subSchedule.`event_id`
) AS Schedule

    ON (`Schedule`.`event_id` = `Event`.`id`)

INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`)
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`)
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`)
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)
WHERE `Event`.`name` IS NOT NULL
AND `Event`.`approval_status_id` = 1
AND `Date`.`start` >= '2011-07-12 16:45:39'
GROUP BY `VenueCity`.`id`
ORDER BY `total` DESC 

@Dave,我似乎无法发表评论,我认为这是因为我是 StackOverflow 的新手。但基本上,您尝试使用子查询执行的操作是构建一个伪表,其中每个事件都有一行。该子查询的结果将像真实表一样在外部查询中使用。我相信您可以通过对 event_id 进行分组,然后使用汇总函数来获取您想要的其他字段来获得您想要的内容。 MIN() 将为您提供最低的 Schedule.id,并且通过 INNER JOIN 到日期和 where 子句,它将是与您的 where 子句匹配的最低 ID。您实际上可以单独测试子查询以对其进行微调。

Try a subquery on the schedules table, something like this would get you one random date (most likely the first date that was entered in the table) for each event. Might need a bit of debugging, but this should get you there...


SELECT COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total,
`VenueCity`.`name`, `VenueCity`.`id`, `VenueCity`.`slug`, `RestaurantCity`.`name`,
`RestaurantCity`.`id`, `RestaurantCity`.`slug` FROM `events` AS `Event`
INNER JOIN 

(SELECT MIN(subSchedule.`id`) AS `id`,subSchedule.`event_id` 
   FROM `schedules` AS subSchedule
   INNER JOIN dates AS subDate ON (subDate.`schedule_id` = subSchedule.`id`)   
   WHERE `subDate`.`start` >= '2011-07-12 16:45:39'
   GROUP BY subSchedule.`event_id`
) AS Schedule

    ON (`Schedule`.`event_id` = `Event`.`id`)

INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`)
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`) LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`)
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`)
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)
WHERE `Event`.`name` IS NOT NULL
AND `Event`.`approval_status_id` = 1
AND `Date`.`start` >= '2011-07-12 16:45:39'
GROUP BY `VenueCity`.`id`
ORDER BY `total` DESC 

@Dave, I don't seem to be able to comment, I assume it's because I'm new to StackOverflow. But basically what you are trying to do with the subquery is build the a pseudo table that has one row for each event. The results of that subquery will be used in the outter query just like a real table. I believe you can get what you want by grouping on the event_id, and then using a summary function to get the other fields you want. MIN() will get you the lowest schedule.id, and with the INNER JOIN to the date and the where clause, it will be the lowest ID that matches your where clause. You can actually test the subquery separately to fine tune it.

瘫痪情歌 2024-11-26 20:49:01

事实证明,我只需要进行一些调整。而不是:

COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total

我使用了这个:

COUNT(DISTINCT Event.id) AS total

所以它仍然按城市分组,但计数是基于事件,而不是城市。应该很容易抓住,但是 - 活到老,学到老! :)

完整查询:

SELECT COUNT(DISTINCT Event.id) AS total, `VenueCity`.`name`, `VenueCity`.`id`, 
`VenueCity`.`slug`, `RestaurantCity`.`name`, `RestaurantCity`.`id`, 
`RestaurantCity`.`slug` FROM `events` AS `Event` 
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`) 
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`) 
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`)  
LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`) 
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`) 
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)  
WHERE `Event`.`name` IS NOT NULL AND `Event`.`approval_status_id` = 1 
AND `Date`.`start` >= '2011-07-12 17:59:24' 
GROUP BY `VenueCity`.`id` ORDER BY `total` DESC 

Turns out, I just needed a bit of a tweak. Instead of:

COUNT(`VenueCity`.`id`) + COUNT(RestaurantCity.id) AS total

I used this:

COUNT(DISTINCT Event.id) AS total

So it's still grouping by the city, but the count is based on the event, not the city. Should have been an easy one to catch, but - live'n'learn! :)

Complete query:

SELECT COUNT(DISTINCT Event.id) AS total, `VenueCity`.`name`, `VenueCity`.`id`, 
`VenueCity`.`slug`, `RestaurantCity`.`name`, `RestaurantCity`.`id`, 
`RestaurantCity`.`slug` FROM `events` AS `Event` 
INNER JOIN schedules AS `Schedule` ON (`Schedule`.`event_id` = `Event`.`id`) 
INNER JOIN dates AS `Date` ON (`Date`.`schedule_id` = `Schedule`.`id`) 
LEFT JOIN restaurants AS `Restaurant` ON (`Restaurant`.`id` = `Event`.`restaurant_id`)  
LEFT JOIN venues AS `Venue` ON (`Venue`.`id` = `Event`.`venue_id`) 
LEFT JOIN cities AS `VenueCity` ON (`Venue`.`city_id` = `VenueCity`.`id`) 
LEFT JOIN cities AS `RestaurantCity` ON (`Restaurant`.`city_id` = `RestaurantCity`.`id`)  
WHERE `Event`.`name` IS NOT NULL AND `Event`.`approval_status_id` = 1 
AND `Date`.`start` >= '2011-07-12 17:59:24' 
GROUP BY `VenueCity`.`id` ORDER BY `total` DESC 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文