Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL选择加入不在列表中_Sql_Postgresql_Join - Fatal编程技术网

PostgreSQL选择加入不在列表中

PostgreSQL选择加入不在列表中,sql,postgresql,join,Sql,Postgresql,Join,该项目使用Postgres 9.3 我的表格(已简化)如下: t_person (30 million records) - id - first_name - last_name - gender t_city (70,000 records) - id - name - country_id t_country (20 records) - id - name t_last_city_visited (over 200 million records) - person_id - ci

该项目使用Postgres 9.3

我的表格(已简化)如下:

t_person (30 million records)
- id
- first_name
- last_name
- gender

t_city (70,000 records)
- id
- name
- country_id

t_country (20 records)
- id
- name

t_last_city_visited (over 200 million records)
- person_id
- city_id
- country_id
  - There is a unique constraint on person_id, country_id to
    ensure that each person only has one last city per country
我需要做的是以下方面的变化:

获取访问过“英国”国家的女性身份证 但从未访问过国家“美国”

我试过以下方法,但速度太慢了

select t_person.id from t_person
join t_last_city_visited
  on (
          t_last_city_visited.person_id = t_person.id
          and country_id = (select id from t_country where name = 'UK')
     )
where gender = 'female'
except
(
    select t_person.id from t_person
    join t_last_city_visited
      on (
             t_last_city_visited.person_id = t_person.id
             and country_id = (select id from t_country where name = 'USA')
         )
)

我非常感谢您的帮助。

提示:您想做的是找到那些有英国之行但没有美国之行的女性

比如:

select ...
from   t_person
where  ...
   and exists (select null
                 from t_last_city_visited join
                      t_country on (...)
                where t_country.name = 'UK')
   and not exists (select null
                 from t_last_city_visited join
                      t_country on (...)
                where t_country.name = 'US')
另一种方法是找到访问过英国而不是美国的人,然后你可以加入这些人,按性别进行筛选:

select   person_id
  from   t_last_city_visited join
         t_country on t_last_city_visited.country_id = t_country.id
 where   t_country.name in ('US','UK')
group by person_id
having   max(t_country.name) = 'UK'

请运行分析并执行此查询,好吗

-- females who visited UK
with uk_person as (
  select distinct person_id
  from t_last_city_visited t
  inner join t_person p on t.person_id = p.id and 'F' = p.gender
  where country_id  = (select id from t_country where name = 'UK')
),
-- females who visited US
us_person as (
  select distinct person_id
  from t_last_city_visited t
  inner join t_person p on t.person_id = p.id and 'F' = p.gender
  where country_id  = (select id from t_country where name = 'US')
)
-- females who visited UK but not US
select uk.person_id
from uk_person uk
left join us_person us on uk.person_id = us.person_id
where us.person_id is null

这是形成此查询的多种方法之一。您可能需要运行它们来找出哪一个运行得最好,并且可能需要进行索引调整以使它们运行得更快。

这是我的方法,您可以稍后用别名替换内部查询,如@zedfoxus所说

select 
    id 
from 
    (SELECT
        p.id id
    FROM
        t_person p JOIN t_last_city_visited lcv
            ON(lcv.person_id = p.id)
        JOIN country c
            ON(lcv.country_id = c.id  and cname = 'UK')
    WHERE
        p.gender = 'female') v JOIN

    (SELECT
        p2.id id
    FROM
        t_person p2 JOIN t_last_city_visited lcv2
            ON(lcv2.person_id = p2.id)
        JOIN country c
            ON(lcv.country_id = c.id  and cname != 'USA')
    WHERE
        p.gender = 'female') nv

        ON(v.id = nv.id)

你还没有提到到底有多慢。所有这些表都有哪些额外的索引?正如Dmitry所说。您必须提供查询的分析结果。并告诉我们需要多少时间。对所有回应-谢谢。所有ID字段上都有索引(因为它们是外键)。可以(在代码中)提前完成(选择id,其中name=x)以不影响查询,因此它只是一个id查找查询。t如果索引设置正确,这可能是最好的改进。@David Aldridge:上面的第二个解决方案非常完美。快得多。非常感谢。虽然您的版本不依赖于我们和英国之间的字符串值吗?@Ask613——是的,确实如此,这是一种非常特殊的情况,可以以一种不一定扩展到其他类似情况的方式优化非常特定的查询。如果您想测试“已访问FR和英国,但未访问美国或CA”,那么您可能会回到基于EXISTS的版本。通过在公共表表达式中获取相关的国家ID并在相关的子查询中使用这些ID,可以进一步优化该方法,以避免连接。@davidridge不一定<代码>具有sum(当t_country.name在('FR','UK')中时为1结尾)=2和sum(当t_country.name在('US','CA')中时为1结尾)=0应执行以下操作trick@Aツ 是的,类似的原则。怎么样访问英国、美国和法国,或(加拿大和德国或墨西哥)?不,只是开玩笑。通常,您可以使用聚合来构建所有这些东西,但每一个都需要一些思考。我猜exists方法也是如此,但对于许多情况,它可能更容易构造。