【问题标题】:INNER JOIN one table with two others as though they were outer joinsINNER JOIN 一个表和另外两个表,就好像它们是外部连接一样
【发布时间】:2016-06-07 19:22:28
【问题描述】:

我在 postgreSQL 9.5 数据库中有三个表:

big_table:
 - geom_location
a:
 - geom_location
 - name
b:
 - geom_location
 - name

geom_location 字段是已编入索引的 postGIS 字段。 a 和 b 表大约有 200K 行,而 big_table 大约有 20M 行。
我需要创建一个产生以下结果的选择语句:

  • a_name - 如果在表 a 的 geom_location 2Km 内有一个 big_table 条目,这将是它的关联名称。否则,它将为空。
  • b_name - 如果在表 b 的 geom_location 2Km 内有一个 big_table 条目,这将是它的关联名称。否则,它将为空。
  • geom_location - 距离表 a、b 或两者中的条目 2 公里范围内的 geom_location。
  • 我不想取回任何 a_name 和 b_name 都为空的行。

以下接近我想要的,但它要求所有三个 geom_locations 都在 2Km 内:

SELECT t.geom_location, a.name as a_name, b.name as b_name
FROM big_table t 
INNER JOIN a ON ST_DWithin(t.geom_location, a.geom_location, 2000) 
INNER JOIN b ON ST_DWithin(t.geom_location, b.geom_location, 2000)

这也非常接近,但它并没有按照我想要的方式组合行:

SELECT t.geom_location, a.name as a_name, null as b_name
FROM big_table t 
INNER JOIN a ON ST_DWithin(t.geom_location, a.geom_location, 2000) 
UNION
SELECT t.geom_location, null as a_name, b.name as b_name
FROM big_table t 
INNER JOIN b ON ST_DWithin(t.geom_location, b.geom_location, 2000)

似乎应该有某种语法来执行“大部分”内连接——也就是说,两个表相对于第一个表将内连接设为内连接,但相对于第一个表进行完全连接彼此。

【问题讨论】:

    标签: sql inner-join postgis


    【解决方案1】:

    这是你想要的吗?

    SELECT t.geom_location, a.name as a_name, b.name as b_name
    FROM big_table t LEFT JOIN
         a
         ON ST_DWithin(t.geom_location, a.geom_location, 2000) LEFT JOIN
         b
         ON ST_DWithin(t.geom_location, b.geom_location, 2000) AND a.name IS NULL
    WHERE a.name IS NOT NULL OR b.name IS NOT NULL;
    

    或者,您可以将ab 组合在一起:

    SELECT t.geom_location, ab.name, ab.which
    FROM big_table t JOIN
         ((SELECT a.name a.geom_location, 'a' as which
           FROM a
          ) UNION ALL
          (SELECT a.name b.geom_location, 'b' as which
           FROM b
          )
         ) ab
         ON ST_DWithin(t.geom_location, ab.geom_location, 2000) ;
    

    编辑:

    我实际上认为上述解决方案可能存在一些性能问题。它适用于简单的数据类型,但复杂的类型总是有点麻烦。但是,你仍然可以做你想做的事。这是您的union 方法的一种变体:

    用 ta 作为 ( SELECT t.geom_location,a.name 作为 a_name,null 作为 b_name FROM big_table t INNER JOIN 一个 ON ST_DWithin(t.geom_location, a.geom_location, 2000 ) 选择 ta.* 来自 ta 联合所有 SELECT t.geom_location,null 作为 a_name,b.name 作为 b_name FROM big_table t INNER JOIN b 在 ST_DWithin(t.geom_location,b.geom_location,2000) 不存在的地方(选择 1 来自 ta WHERE t.geom_location = ta.geom_location );

    我很确定 = 应该在位置列上工作。

    【讨论】:

    • 我认为它会,但不幸的是,在这样的左外连接中使用 ST_DWithin 不会使用它的索引。对该查询的 postgres 解释返回的成本超过 2 万亿!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    相关资源
    最近更新 更多