使用表和子表

时间:2016-08-19 03:50:03

标签: postgresql

我的表格下面是

目标表:

id (int)
user_id (int)
location (string) from Google places
latitude 
longitude
gender  (int) 1 male,2 female, 3 both 
fromdate (date)
todate (date)

目标兴趣表:

_id (int)
goal_id (int)
user_interest__id (int)

所以用户输入目标。我将于2016-08-18至2016-09-18在美国坦帕市寻找男性或女性(3)进行划船(interest_id 3),骑自行车(interest_id 4)和钓鱼(interest_id 6)

我如何在PgSQL中写这个?我阅读了关于联接的一些文档但是不知道处理兴趣中的一对多的最佳方法。用户在创建"目标"时可以输入1到3个兴趣点。

我需要匹配至少有一个类似兴趣的人,将来自坦帕之间的&到日期并且是1或2性别ID。

2 个答案:

答案 0 :(得分:1)

首先要考虑三个问题:

  1. 您的应用程序的逻辑可能是用户的目标和兴趣数据首先存储在表格中,然后搜索匹配目标。因此,以下查询使用自联接和子查询来查找此类匹配。
  2. 您应该使用daterange类型而不是fromdatetodate。 PG有一些强大的日期范围运算符。因此,我假设您的表格会有一个dates daterange列。
  3. 你不应该搜索位置字符串,而是搜索(经度,纬度)对,以及旅行者愿意移动以找到灵魂伴侣的最大距离。否则,圣彼得堡或克利尔沃特的完美比赛将被忽视。为此,您还需要将单独的longitudelatitude列转换为其他类型。您有两种选择:轻量级选择是使用内置point类型,然后使用CREATE EXTENSION earthdistance。在(lon,lat)单位中的两个点上使用<@>运算符将在法定里程中给出距离。或者,更强大的PostGIS扩展可以与CREATE EXTENSION postgis一起使用,然后您使用geography类型作为经度和纬度。我将在这里使用第一个选项,因为它是最直接的,可能对你来说足够好。因此,您将拥有loc point列,而不是经度和纬度。
  4. 然后查询变为:

    SELECT g2.*, g1.loc <@> g2.loc AS distance, i.interests
    FROM goals g1  -- the traveler
    JOIN goals g2  -- the soul mate
      ON (g2.loc <@> g1.loc) <= [[maximum distance in miles]]
     AND g2.dates && g1.dates -- dates must overlap (possibly partially)
     AND (g2.gender = 3 OR g2.gender = [[gender of user]])
    JOIN (
      SELECT goal_id, array_agg(user_interest__id) AS interests
      FROM goal_interests
      WHERE user_interest__id IN (3, 4, 6) -- or whatever your interest are
      GROUP BY goal_id
    ) i ON i.goal_id = g2.id;
    

    此查询为您提供goal表格中的所有匹配数据,每场比赛的一行,以及与比赛的距离和共同兴趣。

答案 1 :(得分:0)

试试这个:

select
    g.user_id 
from
    goals g
join
    goal_interests gi on g.id = gi.goal_id 
where
    g.location = 'Tampa FL US' and
    g.fromdate >= '2016-08-18' and
    g.todate <= '2016-09-18' and
    g.gender in (1,2) and
    gi.user_interest__id in (3,4,6)