代码之家  ›  专栏  ›  技术社区  ›  Chase Seibert

混合隐式和显式联接

  •  8
  • Chase Seibert  · 技术社区  · 15 年前

    我在生成无效的SQL时遇到了Hibernate问题。具体来说,混合和匹配隐式和显式连接。这似乎是一个 open bug .

    但是,我不确定 为什么? 这是无效的SQL。我想出了一个小的玩具例子,它生成了相同的语法异常。

    图式

    CREATE TABLE Employee (
        employeeID INT,
        name VARCHAR(255),
        managerEmployeeID INT   
    )
    

    数据

    INSERT INTO Employee (employeeID, name) VALUES (1, 'Gary')
    INSERT INTO Employee (employeeID, name, managerEmployeeID) VALUES (2, 'Bob', 1)
    

    工作SQL

    这两个查询都有效。我知道有笛卡尔积,这是故意的。

    显式连接:

    SELECT e1.name,
           e2.name,
           e1Manager.name
      FROM Employee e1
     CROSS JOIN Employee e2
     INNER JOIN Employee e1Manager
        ON e1.managerEmployeeID = e1Manager.employeeID
    

    隐式连接:

    SELECT e1.name,
           e2.name,
           e1Manager.name
      FROM Employee e1,
           Employee e2,
           Employee e1Manager
     WHERE e1.managerEmployeeID = e1Manager.employeeID
    

    无效SQL

    此查询不适用于MSSQL 2000/2008或MySQL:

    SELECT e1.name, 
           e2.name, 
           e1Manager.name
      FROM Employee e1,
           Employee e2
     INNER JOIN Employee e1Manager 
        ON e1.managerEmployeeID = e1Manager.employeeID
    

    在MS2000中,我得到错误:

    列前缀“e1”不匹配 使用了表名或别名 在查询中。

    在MySQL中,错误是:

    未知列“e1.ManagerEmployeeID” 在“on子句”中。

    问题(s)

    1. 为什么这个语法无效?
    2. 奖金: 有没有一种方法可以强制Hibernate只使用显式连接?

    3 回复  |  直到 11 年前
        1
  •  12
  •   Bill Karwin    15 年前

    它会导致错误,因为根据SQL标准, JOIN 关键字的优先级高于逗号。关键是表别名在 之后 相应的表已在 FROM 条款。

    所以当你提到 e1 在你 JOIN...ON 表达式, E1 还不存在。

    我研究冬眠的时候请你站在旁边,看看你能不能说服它使用 加入 在所有情况下。


    嗯,hibernate.org网站上的所有内容似乎都被重定向到jboss.org。所以现在没有办法在线阅读HQL文档。我相信他们最终会知道他们的名字。

        2
  •  0
  •   araqnid    15 年前

    PostgreSQL也会出错:

    ERROR:  invalid reference to FROM-clause entry for table "e1"
    LINE 7:     ON e1.managerEmployeeID = e1Manager.employeeID;
                   ^
    HINT:  There is an entry for table "e1", but it cannot be referenced from this part of the query.
    

    我认为问题在于,当您连接两个表A和B(在本例中是e2和e1manager)时,您只能在“on”子句中引用这两个表。所以您可以在这个on子句中引用e2和e1manager,但不能引用e1。

    我认为这是扩展的,因此如果您有一个“join”语句链,那么您可以在“on”子句中引用同一链中的其他表,但是您不能跨越“,”。因此允许类似“a.a上的join b”id=b.a_id在c.b_id=b.b_id和c.a_id=a.a_id”的情况。

    您用于生成此SQL的HQL是什么?比如“从员工e1,员工e2中选择e1.name,e2.name,e1.manager.name”?

        3
  •  0
  •   Community Egal    7 年前

    这可能有点离题,因为它根本不涉及Hibernate,但是来自 Bill Karwin 真的睁开了眼睛。您不需要先编写隐式连接,而是需要先执行显式连接。如果您有多个隐式连接,这种语法尤其有趣。

    在MS SQL中检查以下示例。并非所有联系人都定义了国家/地区代码,但所有联系人都有一个将在表tbl中查找的属性val。因此,直观的解决方案将不起作用:

    SELECT * FROM 
    contacts, Tbl
    LEFT OUTER JOIN country ON CtryCod = country.CtryCod 
    WHERE val = Tbl.val
    

    相反,您可能希望使用以下语法:

    SELECT * FROM 
    contacts LEFT OUTER JOIN country ON CtryCod = country.CtryCod, 
    Tbl
    WHERE val = Tbl.val