【问题标题】:SQL - understanding 'JOIN' syntax, orderSQL - 理解 'JOIN' 语法、顺序
【发布时间】:2013-10-04 21:13:33
【问题描述】:

我的任务之一是将访问 SQL 转换为 Oracle SQL。 我在 MS Access 中运行了查询,这里是关系表、查询 SQL 和查询结果:

访问查询 SQL

SELECT PUBLISHER.PUBLISHER_CODE, PUBLISHER.PUBLISHER_NAME, BOOK.TITLE, BOOK.TYPE, INVENTORY.BRANCH_NUM, BRANCH.BRANCH_NAME
FROM PUBLISHER INNER JOIN (BRANCH INNER JOIN (BOOK INNER JOIN INVENTORY ON BOOK.BOOK_CODE = INVENTORY.BOOK_CODE) ON BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM) ON PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
WHERE (((BOOK.TYPE)='FIC') AND ((BRANCH.BRANCH_NAME)='Henry on the Hill'))
ORDER BY PUBLISHER.PUBLISHER_NAME;

想到MS SQL可能在oracle中也能用,我试了一下:

SQL> SELECT PUBLISHER.PUBLISHER_CODE, PUBLISHER.PUBLISHER_NAME, BOOK.TITLE, BOOK.TYPE, INVENTORY.BRANCH_NUM, BRANCH.BRANCH_NAME
  2  FROM PUBLISHER INNER JOIN (BRANCH INNER JOIN (BOOK INNER JOIN INVENTORY ON BOOK.BOOK_CODE = INVENTORY.BOOK_CODE) ON BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM) ON PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
  3  WHERE (((BOOK.TYPE)='FIC') AND ((BRANCH.BRANCH_NAME)='Henry on the Hill'))
  4  ORDER BY PUBLISHER.PUBLISHER_NAME;

no rows selected

显然这没有用。 所以,我在我的 oracle 11g 中做了一个剪切/粘贴/编辑的事情。这是我得到的:

SQL> SELECT PUBLISHER.PUBLISHER_CODE, PUBLISHER.PUBLISHER_NAME, BOOK.TITLE, BOOK.TYPE,
  2   INVENTORY.BRANCH_NUM, BRANCH.BRANCH_NAME
  3  FROM PUBLISHER
  4   inner join BOOK  ON PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
  5  inner join INVENTORY on INVENTORY.BRANCH_NUM = BRANCH.BRANCH_NUM
  6  inner join BRANCH on INVENTORY.BRANCH_NUM = BRANCH.BRANCH_NUM
  7   where BOOK.BOOK_TYPE = 'FIC'
  8   and BRANCH.BRANCH_NAME = 'Henry on the Hill';
inner join INVENTORY on INVENTORY.BRANCH_NUM = BRANCH.BRANCH_NUM
                                               *
ERROR at line 5:
ORA-00904: "BRANCH"."BRANCH_NUM": invalid identifier

那么为什么我会得到这个: 第 5 行的错误: ORA-00904: "BRANCH"."BRANCH_NUM": 标识符无效

连接的顺序会影响什么吗? 如您所见,我确实按顺序从一张桌子到另一张桌子。

语法顺序重要吗?例如:

INVENTORY.BRANCH_NUM = BRANCH.BRANCH_NUM 上的内部连接 ​​BRANCH BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM 上的内部连接 ​​BRANCH

这有关系吗?

Oracle SQL 中的连接格式是否正确,顺序是否正确?

如果是,为什么不运行?


旁注,这是一个在线课程,虽然讲师很专心,但我在这里通过阅读其他帖子和提出自己的问题学到了很多东西。谢谢大家!

【问题讨论】:

    标签: mysql sql oracle ms-access-2010


    【解决方案1】:

    连接顺序很重要,例如check this answer。您无法访问未在条件之前引入的表别名,例如您无法在第 5 行访问BRANCH,因为它仅在下一个联接中引入。

    MS Access 的代码引入了很多括号来限制连接顺序。只需对其应用格式并查看结果:

    SELECT
      PUBLISHER.PUBLISHER_CODE,
      PUBLISHER.PUBLISHER_NAME,
      BOOK.TITLE,
      BOOK.TYPE,
      INVENTORY.BRANCH_NUM,
      BRANCH.BRANCH_NAME
    FROM
      PUBLISHER
      INNER JOIN (
        BRANCH INNER JOIN (
          BOOK INNER JOIN INVENTORY
            ON BOOK.BOOK_CODE = INVENTORY.BOOK_CODE
          )
          ON BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM
        )
        ON PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
    WHERE
      (
        (
          (BOOK.TYPE)='FIC'
        )
        AND
        (
          (BRANCH.BRANCH_NAME)='Henry on the Hill'
        )
      )
    ORDER BY
      PUBLISHER.PUBLISHER_NAME
    

    删除不需要的括号后如下所示:

    SELECT
      PUBLISHER.PUBLISHER_CODE,
      PUBLISHER.PUBLISHER_NAME,
      BOOK.TITLE,
      BOOK.TYPE,
      INVENTORY.BRANCH_NUM,
      BRANCH.BRANCH_NAME
    FROM
      PUBLISHER
      INNER JOIN BRANCH
      INNER JOIN BOOK
      INNER JOIN INVENTORY
                 ON BOOK.BOOK_CODE = INVENTORY.BOOK_CODE
                    AND
                    BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM
                    AND
                    PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
    WHERE
      BOOK.TYPE='FIC'
      AND
      (BRANCH.BRANCH_NAME = 'Henry on the Hill')
    ORDER BY
      PUBLISHER.PUBLISHER_NAME
    

    看起来更好,但可以通过将 ANSI 语法转换为普通查询来避免排序问题:
    警告:ANSI 语法很有趣,请不要阅读此答案的其余部分 :-)

    SELECT
      PUBLISHER.PUBLISHER_CODE,
      PUBLISHER.PUBLISHER_NAME,
      BOOK.TITLE,
      BOOK.TYPE,
      INVENTORY.BRANCH_NUM,
      BRANCH.BRANCH_NAME
    FROM
      PUBLISHER,
      BRANCH,
      BOOK,
      INVENTORY
    WHERE
      BOOK.TYPE='FIC'
      AND
      (BRANCH.BRANCH_NAME = 'Henry on the Hill')
      AND
      PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
      AND
      BOOK.BOOK_CODE = INVENTORY.BOOK_CODE
      AND
      BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM
    ORDER BY
      PUBLISHER.PUBLISHER_NAME
    

    使用这种不同的条件顺序无关紧要,所有条件都放在一起,因此可以按逻辑顺序重新组织它:

    SELECT
      PUBLISHER.PUBLISHER_CODE,
      PUBLISHER.PUBLISHER_NAME,
      BOOK.TITLE,
      BOOK.TYPE,
      INVENTORY.BRANCH_NUM,
      BRANCH.BRANCH_NAME
    FROM
      BRANCH,
      INVENTORY,
      BOOK,
      PUBLISHER
    WHERE
      (BRANCH.BRANCH_NAME = 'Henry on the Hill') -- start from most restrictive 
                                                 -- condition (concrete branch)  
      AND
      INVENTORY.BRANCH_NUM = BRANCH.BRANCH_NUM   -- get all inventory from this branch
      AND
      BOOK.BOOK_CODE = INVENTORY.BOOK_CODE       -- access book specification 
                                                 -- corresponding to inventory
      AND    
      BOOK.TYPE = 'FIC'                          -- of specific type 
      AND
      PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE  -- and finally find 
                                                      -- all publishers of that books
    ORDER BY
      PUBLISHER.PUBLISHER_NAME
    

    因此,在最后一个变体中,可以以人类可读的格式重现查询逻辑。
    请注意,查询文本中的表顺序(如果您不使用一些特殊提示,至少在 Oracle 中)不会影响真正的查询执行计划,因为优化器会根据需要自行更改它。因此,在大多数情况下,ANSI 变体只是引入了语法限制而没有真正的帮助。

    【讨论】:

    • 您的声明 “因此,在大多数情况下,ANSI 变体只是引入了语法限制而没有真正的帮助” 听起来您已经证明了这一点,但就目前而言,您实际上还没有我可以告诉。 IMO ANSI 查询语法在可读性和清晰度方面要好得多,更能自我记录(例如预期的连接类型),并且更擅长防止连接中的错误(例如缺少连接),而您的方法永远无法捕捉到这些错误。最重要的是,我发现您的格式更难阅读,并且带有多余的 cmets,例如“对应于库存”,这在 ANSI 语法中非常清楚。
    • @RedFilter 似乎您在答案的中间错过了一个警告:) 对于不同的人来说,这是不同的笔触。所以 IMO 是两种观点的最佳资格。
    【解决方案2】:

    您的原始查询像这样加入了 INVENTORY:

    inner join INVENTORY ON BOOK.BOOK_CODE = INVENTORY.BOOK_CODE
    

    试试这个:

    select PUBLISHER.PUBLISHER_CODE, PUBLISHER.PUBLISHER_NAME, BOOK.TITLE, BOOK.TYPE, INVENTORY.BRANCH_NUM, BRANCH.BRANCH_NAME
    from PUBLISHER
    inner join BOOK on PUBLISHER.PUBLISHER_CODE = BOOK.PUBLISHER_CODE
    inner join INVENTORY on BOOK.BOOK_CODE = INVENTORY.BOOK_CODE
    inner join BRANCH on BRANCH.BRANCH_NUM = INVENTORY.BRANCH_NUM
    where BOOK.TYPE = 'FIC'
        and BRANCH.BRANCH_NAME = 'Henry on the Hill'
    order by PUBLISHER.PUBLISHER_NAME;
    

    【讨论】:

    • 我仍然得到“未选择行”,这对我来说没有意义。
    • 如果您提供一些示例数据和架构,我可以进一步帮助您。 SQL Fiddle 让这一切变得简单。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 2012-07-29
    • 2015-05-27
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多