sql - PostgreSQL:自引用、扁平化连接到包含对象树的表

标签 sql postgresql join tree self-reference

我有一个相对较大(如 >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/

相关文章:

sql - SQL中每3行生成一个序列号

sql - 使用 SQL 有效地反转外键

json - 在 postgresql 中处理 Unicode 序列

c# - 具有多个连接的 Linq 查询未给出正确的结果

java - Java 中的 Spark 在进行 join 或 groupWith 时如何比较两个键?

mysql - 这与 MYSQL 查询中的 JOIN 相同吗?

mysql在select中选择一个值

mysql - MySql 连接的限制

postgresql - Gorm 与 Postgres 客户端过多问题

mysql - 从两个表中选择数据