【问题标题】:Doing a left join with old style joins使用旧式连接进行左连接
【发布时间】:2019-01-07 09:30:07
【问题描述】:

所以我目前正在将 OracleSQL 转录到一个新的 PostgreSQL 数据库中。虽然我正在将 Oracle 的 (+) 连接转换为 LEFT OUTER JOINs,但效果很好。

与旧式连接组合时除外。以这个 OracleSQL 为例:

SELECT
    *
FROM
    table1,
    table2 alias1,
    table2 alias2,
    table2 alias3,
    table3,
    table4,
    table5,
    table6 table6alias
WHERE
    table1.id_table3 = alias1.id_table3
    AND table1.id_table4 = alias2.id_table4
    AND table1.id_table3 = table3.id_table3
    AND table1.id_table4 = table4.id_table4
    AND table1.id_table5 = table5.id_table5
    AND table1.table1_id_table3_sender = alias3.id_table3 (+)
    AND alias1.id_svw_uebertragungsweg = table6alias.id_svw
    AND table1.id_table3 != 0
    AND ( table1.id_usr = 0
          OR table1.id_usr IS NULL )

它在 Oracle 的 SQL Developer 上运行良好。所以我试着像这样转录它:

SELECT
    *
FROM
    table1,
    table2 alias1,
    table2 alias2,
    table3,
    table4,
    table5,
    table6 table6alias
LEFT OUTER JOIN table2 alias3
ON table1.table1_id_table3_sender = alias3.id_table3
WHERE
    table1.id_table3 = alias1.id_table3
    AND table1.id_table4 = alias2.id_table4
    AND table1.id_table3 = table3.id_table3
    AND table1.id_table4 = table4.id_table4
    AND table1.id_table5 = table5.id_table5
    AND alias1.id_svw_uebertragungsweg = table6alias.id_svw
    AND table1.id_table3 != 0
    AND ( table1.id_usr = 0
          OR table1.id_usr IS NULL )

给我这个错误:

ORA-00904: "table1"."table1_id_table3_sender": 无效标识符 00904. 00000 - “%s:无效标识符” *原因:
*行动: 在线错误:12 行:8

我已经完成了 JOIN,然后它就完美地工作了。当只添加一个其他 JOIN 时,它给了我这个错误,即找不到该行(无效的标识符)。

我已经在互联网上读到 LEFT JOIN 不会比 FROM 语句的第一个表更红。但在这种情况下,这就足够了(在我看来)——也只是添加另一个表会导致错误。

那么我有什么方法来解决这个到 PostgreSQL 的翻译问题?我是否必须将所有旧样式的 JOIN 重写为新样式的 JOIN(这将非常乏味,因为这些 SELECT 有很多),还是有什么我没有注意到的?

【问题讨论】:

  • 不要混合隐式连接和显式连接
  • 今日提示:始终使用现代、明确的JOIN 语法。更容易编写(没有错误),更容易阅读和维护,如果需要更容易转换为外连接!
  • 显式 JOIN 在隐式、逗号分隔的连接之前进行评估。这意味着您的 ON 子句只能访问 table6 和 table2 列。
  • 是的,最好重写以使用显式 JOINS;当您可以轻松解决使维护变得容易的问题时,付出的努力是值得的
  • @Damien_The_Unbeliever 的回答回答了我的最后一个问题。

标签: sql postgresql left-join inner-join database-migration


【解决方案1】:

不要混合显式和隐式 JOIN。事实上,不要使用隐式 JOIN。

这是您想要的查询:

SELECT
    *
FROM
    table1
    INNER JOIN table2 alias1 ON table1.id_table3 = alias1.id_table3 
    INNER JOIN table2 alias2 ON table1.id_table4 = alias2.id_table4
    INNER JOIN table3 ON table1.id_table3 = table3.id_table3
    INNER JOIN table4 ON table1.id_table4 = table4.id_table4
    INNER JOIN table5 ON table1.id_table5 = table5.id_table5
    INNER JOIN table6 table6alias ON alias1.id_svw_uebertragungsweg = table6alias.id_svw
    LEFT JOIN table2 alias3 ON table1.table1_id_table3_sender = alias3.id_table3
WHERE
    table1.id_table3 != 0
    AND ( table1.id_usr = 0 OR table1.id_usr IS NULL )

【讨论】:

    【解决方案2】:

    问题是(不确定它是否是标准的,但大多数数据库引擎似乎都遵循它)显式连接在 隐式连接之前处理。在您进行连接时,范围内的唯一表/别名是table6aliasalias3。但是您尝试在您的 ON 子句中引用 table1 以进行连接。

    正如您所怀疑的,解决方案是在整个过程中使用显式联接,这也使您可以更好地控制联接发生的顺序。

    (或者快速解决方法是将LEFT JOIN 放在alias3 之后紧跟table1

    【讨论】:

    • "显式连接在 隐式连接之前处理" - 哦,我测试了一下,这正是正在发生的事情。这对我理解我的 SELECT 有很大帮助,谢谢!
    • @Damien_The_Unbliever 。 . . FROM 中的逗号运算符的优先级低于 JOIN - 这是基于标准的。所以先处理逗号的“边”,这就是表别名无法识别的原因。
    【解决方案3】:

    你的加入不正确应该是这样的:

    SELECT
     *
    FROM
     table1 left outer join table2 alias3 on table1.table1_id_table3_sender = 
     alias3.id_table3,
     table2 alias1,
     table2 alias2,
     table3,
     table4,
     table5,
     table6 table6alias
    WHERE
    table1.id_table3 = alias1.id_table3
    AND table1.id_table4 = alias2.id_table4
    AND table1.id_table3 = table3.id_table3
    AND table1.id_table4 = table4.id_table4
    AND table1.id_table5 = table5.id_table5
    AND alias1.id_svw_uebertragungsweg = table6alias.id_svw
    AND table1.id_table3 != 0
    AND ( table1.id_usr = 0
          OR table1.id_usr IS NULL )
    

    【讨论】:

      猜你喜欢
      • 2020-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-29
      • 2013-01-30
      • 1970-01-01
      • 2015-04-13
      相关资源
      最近更新 更多