我有一个相对较大(如 >10^6 条目)的表,称为“things”,它表示可定位的对象,例如国家、地区、城市、街道等。它们被用作具有固定深度的对象树,因此表结构如下所示:
id
name
type
continent_id
country_id
city_id
area_id
street_id
etc.
“事物”内部的关联是 1:n,即一条街道或区域总是属于一个定义的城市和国家(而不是两个或一个都没有);例如,city_id 列包含该城市内所有对象的“城市”事物的 id。 “type”列包含事物的类型(街道、城市等)作为字符串。
该表在另一个表“actions”中被引用为“thing_id”。我正在尝试生成一个操作位置统计数据表,显示给定位置的事件和非事件操作数量。一个简单的 JOIN 就像
SELECT count(nullif(actions.active, 1)) AS icount, count(nullif(actions.active, 0)) AS acount, things.name AS name, things.id AS thing_id, things.city_id AS city_id FROM "actions" LEFT JOIN things ON actions.thing_id = things.id WHERE UPPER(substring(things.name, 1, 1)) = UPPER('A') AND actions.datetime_at BETWEEN '2012-09-26 19:52:14' AND '2012-10-26 22:00:00' GROUP BY things.name, things.id ORDER BY things.name
will give me a list of "things" (starting with 'A') which have actions associated with them and their active and inactive count like this:
icount | acount | name | thing_id | city_id
------------------------------------------------------------------
0 5 Brooklyn, New York City | 25 | 23
1 0 Manhattan, New York City | 24 | 23
3 2 New York City | 23 | 23
现在我愿意
- 仅考虑“城市”事物(这很简单:按“事物”类型进行过滤),并且
- 在事件/非事件计数中,使用该城市中发生的所有操作的总和 - 无论该操作是与城市本身相关还是与城市内部的某些内容相关(= 具有相同的 city_id )。使用与上面相同的数据集,新查询应产生
icount | acount | name | thing_id | city_id ------------------------------------------------------------------ 4 7 New York City | 23 | 23
我不需要此表中的 thing_id(因为它无论如何都不会是唯一的),但由于我确实需要城市名称(用于显示),因此可能也很容易输出 ID,那么我就不必在代码中进行太多更改。
我必须如何修改上述查询才能实现此目的?如果可能的话,我希望避免额外访问数据库以及高级 SQL 功能,例如过程、触发器、 View 和临时表。
我在 Rails 3.0.14(在 Mac OS X 10.7.4 上)上使用 Postgres 8.3 和 Ruby 1.9.3。
谢谢! :)
最佳答案
您需要在独立子查询中计算城市中所有事物的操作,然后然后连接到一组有限的事物:
SELECT c.icount
,c.acount
,t.name
,t.id AS thing_id
,t.city_id
FROM (
SELECT t.city_id
,count(nullif(a.active, 1)) AS icount
,sum(a.active) AS acount
FROM things t
LEFT JOIN actions a ON a.thing_id = t.id
WHERE t.city_id = 23 -- to restrict results to one city
GROUP BY t.city_id
) c -- counts per city
JOIN things t USING (city_id)
WHERE t.name ILIKE 'A%'
AND t.datetime_at BETWEEN '2012-09-26 19:52:14'
AND '2012-10-26 22:00:00'
ORDER BY t.name, t.id;
我还简化了查询中的许多其他内容,并使用表别名以使其更易于阅读。
关于sql - PostgreSQL:自引用、扁平化连接到包含对象树的表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12610429/