【问题标题】:Postgresql : How to join with multiple cross-reference table?Postgresql:如何加入多个交叉引用表?
【发布时间】:2013-07-26 06:58:54
【问题描述】:

我看过很多关于多个 JOIN 的帖子,但它对我的情况没有帮助。

假设我有三个表和两个交叉引用表。这与其他帖子的不同之处在于他们在 FROM 中有多个表但有一个交叉引用表。

Table1 -> cross-ref1 cross-ref2

我的 Postgresql 版本是:9.0.11,我正在使用 W7 64 位。

我的要求如下:

Select [columns] from cross-ref1, cross-ref2

INNER JOIN table1 ON table1.id_table1=cross-ref1.ref_id_table1

INNER JOIN table2 ON table2.id=cross-ref1.ref_id_table2

INNER JOIN table2 On table2.id_table2=cross-ref2.ref_id_table2

INNER JOIN table3 ON table3.id_table3=cross-ref2.ref_id_table3

错误信息是:“表名被指定了多次。”

你能解释一下错误吗?

谢谢

【问题讨论】:

  • 您遇到的错误是什么?在您的数据库上执行该查询的结果是什么?
  • 请查看stackoverflow.com/tags/postgresql/info 的“提出更好的问题”部分,然后使用select version() 输出、完整、准确的错误文本 等编辑您的问题,然后完成后在这里评论。如果可能,提供一个测试用例,其中包含sqlfiddle.com 上的样本数据
  • 当然不行”不是有效的 Postgres 错误消息。

标签: postgresql join


【解决方案1】:

交叉引用表需要单独的列用于引用的每一侧。只有一列的外部参照表没有意义,因为它只能引用每一侧具有相同 ID 的行。

典型的设置是:

CREATE TABLE a (
    id integer primary key,
    avalue text not null
);

CREATE TABLE b (
    id integer primary key,
    bvalue text not null
);

CREATE TABLE ab (
     a_id integer references a(id),
     b_id integer references b(id),
     PRIMARY KEY(a_id, b_id)
);

给定样本数据:

INSERT INTO a(id, avalue) VALUES 
(1, 'a1'), (2, 'a2'), (3, 'a3'), (4, 'a4');

INSERT INTO b(id, bvalue) VALUES 
(41, 'b1'), (42, 'b2'), (43, 'b3');

INSERT INTO ab(a_id, b_id) VALUES
(1, 41), (1, 42), (2, 43);

您会发现 ab 与:

SELECT avalue, bvalue
FROM a
INNER JOIN ab ON (a.id = ab.a_id)
INNER JOIN b ON (b.id = ab.b_id);

这里的关键是您在a 一侧加入ab.a_id,在b 一侧加入ab.b_id。在此处观看演示:http://sqlfiddle.com/#!12/3228a/1

这几乎是“多对多表关系 101”,因此可能值得对介绍性 SQL 和关系数据库教程和文档进行更多研究。

【讨论】:

    【解决方案2】:

    您不能两次使用相同的表名 (table2)。在这种情况下,您需要使用 t1、t2a、t2b、...等别名

    SELECT
        ...
    FROM
       table1 AS t1
       INNER JOIN table2 AS t2a
          ON t2a.id= ...
       INNER JOIN table2 AS t2b
          ON t2b.id= ...
       INNER JOIN table3 AS t3
          ON t3.id= ...
       ...
    

    现在你可以加入任何你想加入的东西,你想加入多少次等等。

    【讨论】:

      【解决方案3】:

      你必须解释你想要的结果。例如下面的 SQL 从语法角度是有效的,从业务角度不确定:

      -- this will create sample data with 5 tables
      with 
      crossref1(ref_id) as (VALUES (1),(2),(3)),
      crossref2 (ref_id) as (VALUES (2),(3),(4)),
      table1 (ref_id) as (VALUES (3),(4),(5)),
      table2 (ref_id) as (VALUES (1),(2),(3)),
      table3 (ref_id) as (VALUES (1),(2),(3))
      
      
      -- valid SQL based on your example
      select * from 
      crossref1  
      cross join crossref2
      join table1 on table1.ref_id=crossref1.ref_id
      join table2 as t2_1 on t2_1.ref_id=crossref1.ref_id
      join table2 as t2_2 on t2_2.ref_id=crossref2.ref_id
      join table3 on table3.ref_id=crossref2.ref_id
      

      你的 SQL 有两个问题:

      • 你有两个对table2的引用,你必须添加别名
      • 您必须使用cross join 语法而不是,

      如果您想了解with 的工作原理(我是如何创建示例数据的),PostgreSQL 在这方面有出色的documentation

      【讨论】:

      • 快速提示:如果你想在 Pg 中对样本数据使用 CTE,你可以使用 WITH blah(col1, col2) AS (VALUES(1,2),(3,4,),(5,6)) 代替。更简洁,IMO 更清晰。如果您打算使用 CTE 而不是 CREATE TABLEINSERT 来获取样本数据,那么有必要解释一下发生了什么,因为大多数新用户甚至从未见过 WITH - 如果他们问的是关于INNER JOIN 他们是新用户。
      猜你喜欢
      • 1970-01-01
      • 2014-04-08
      • 1970-01-01
      • 2019-03-09
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多