2

我有一个相对较大的(如 >10^6 个条目)表,称为“事物”,它代表可定位的对象,例如国家、地区、城市、街道等。它们用作具有固定深度的对象树,所以表结构如下所示:

id
name
type
continent_id
country_id
city_id
area_id
street_id
etc.

“事物”内部的关联是 1:n,即一条街道或区域始终属于一个定义的城市和国家(不是两个或没有);例如,city_id 列包含该城市内所有对象的“城市”事物的 id。“类型”列以字符串形式包含事物的类型(街道、城市等)。

该表在另一个表“actions”中被引用为“thing_id”。我正在尝试生成一个动作位置统计表,显示给定位置具有的活动和非活动动作的数量。一个简单的 JOIN 像

SELECT count(nullif(actions.active, 1)) 作为 icount,
       count(nullif(actions.active, 0)) 作为一个计数,
       things.name AS name, things.id AS thing_id, things.city_id AS city_id
  从“行动”
  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

会给我一个“事物”列表(以“A”开头),这些事物具有与它们相关的操作以及它们的活动和非活动计数,如下所示:

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 | 帐户 | 姓名 | thing_id | city_id
-------------------------------------------------- ----------------
     4 7 纽约市 | 23 | 23

我不需要这个表中的thing_id(因为它不会是唯一的),但是因为我确实需要城市的名称(用于显示),所以输出ID可能同样容易,那么我没有在我的代码中进行尽可能多的更改。

我将如何修改上述查询来实现这一点?如果可能的话,我想避免额外访问数据库和高级 SQL 功能,例如过程、触发器、视图和临时表。

我在 Rails 3.0.14(在 Mac OS X 10.7.4 上)上使用 Postgres 8.3 和 Ruby 1.9.3。

谢谢!:)

4

1 回答 1

2

您需要在一个独立的子查询中计算城市中所有事物的操作,然后加入一组有限的事物:

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;

我还简化了查询中的许多其他内容,并使用表别名使其更易于阅读。

于 2012-09-26T22:00:18.187 回答