【问题标题】:how to prevent duplicates with inner join query (Postgres)如何使用内部连接查询(Postgres)防止重复
【发布时间】:2013-07-31 07:45:31
【问题描述】:

我正在尝试了解如何创建查询以根据内部联接过滤掉一些结果。

考虑以下数据:

formulation_batch
-----
id  project_id  name    
1   1           F1.1
2   1           F1.2
3   1           F1.3
4   1           F1.all

formulation_batch_component
-----
id  formulation_batch_id    component_id
1   1                       1
2   2                       2
3   3                       3
4   4                       1
5   4                       2
6   4                       3
7   4                       4

我想选择 project_id 为 1 的所有 Formulation_batch 记录,并且有一个 component_id 为 1 或 2 的 Formulation_batch_component。所以我运行以下查询:

SELECT formulation_batch.* 
FROM formulation_batch 
INNER JOIN formulation_batch_component
ON formulation_batch.id = formulation_batch_component.formulation_batch_id
WHERE formulation_batch.project_id = 1 
    AND ((formulation_batch_component.component_id = 2 
        OR formulation_batch_component.component_id = 1 ))

但是,这会返回一个重复的条目:

1;"F1.1"
2;"F1.2"
4;"F1.all"
4;"F1.all"

有没有办法修改这个查询,以便我只取回符合条件的唯一的formulation_batch 记录?

EG:

1;"F1.1"
2;"F1.2"
4;"F1.all"

感谢您的宝贵时间!

【问题讨论】:

    标签: sql postgresql inner-join


    【解决方案1】:

    一种方法是使用distinct:

    SELECT distinct "formulation_batch".* 
    FROM "formulation_batch" 
    INNER JOIN "formulation_batch_component" 
    ON "formulation_batch"."id" = "formulation_batch_component"."formulationBatch_id" 
    WHERE "formulation_batch"."project_id" = 1 
        AND (("formulation_batch_component"."component_id" = 2 
            OR "formulation_batch_component"."component_id" = 1 ))
    

    【讨论】:

    • 谢谢,我忘了区分。它不是最好的性能,但仍然比在软件级别过滤它要好。
    【解决方案2】:

    在这种情况下,可以在join 之前应用distinct,这可能会提高性能:

    select fb.* 
    from
        formulation_batch fb
        inner join
        (
            select distinct formulationbatch_id
            from formulation_batch_component
            where component_id in (1, 2)
        ) fbc on fb.id = fbc.formulationbatch_id 
    where fb.project_id = 1
    

    注意如何为表名使用别名以使查询更清晰。然后in 运算符非常方便。没有必要在这些标识符中使用双引号。

    【讨论】:

    • 感谢您对优化的想法。查询实际上是由 ORM 生成的,但我认为我有办法像这样实现它(与我修改它以在外部查询中选择 distinct 的方式大致相同)。
    • 在我的测试中,像上面这样的内连接也比在 where 子句中使用 formulabatch_ids 更快,即:select fb.* from formulation_batch fb where fb.project_id = 1 AND fb.id IN ( select formulationbatch_id from formulation_batch_component where component_id in (1, 2) )
    【解决方案3】:

    我知道问题询问如何使用内部连接防止重复,但可以在谓词中使用 IN 子句。

    SELECT "formulation_batch".* 
    FROM "formulation_batch" fb
    ON "formulation_batch"."id" = "formulation_batch_component"."formulationBatch_id" 
    WHERE "formulation_batch"."project_id" = 1 
     AND fb.id IN (SELECT "formulation_batch"."id"
                   FROM formulation_batch_component
                   WHERE (("formulation_batch_component"."component_id" = 2 
                          OR "formulation_batch_component"."component_id" = 1 ))
    

    【讨论】:

    • 这是我试图提出的问题的最佳解决方案。干杯!
    • 我测试了这个和@Clodoaldo Neto 的答案,在我的情况下,内部连接的速度快了约 50%
    猜你喜欢
    • 2013-01-31
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    相关资源
    最近更新 更多