8

我遇到了 Hibernate 生成无效 SQL 的问题。具体来说,混合和匹配隐式和显式连接。这似乎是一个开放的错误

但是,我不确定为什么这是无效的 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 中,错误是:

“on 子句”中的未知列“e1.managerEmployeeID”。

问题)

  1. 为什么这个语法无效?
  2. 奖励:有没有办法强制 Hibernate 只使用显式 JOIN?

4

3 回答 3

15

它会导致错误,因为根据 SQL 标准,JOIN关键字的优先级高于逗号。关键点是表别名直到FROM子句 中评估了相应的表之后才可用。

因此,当您e1JOIN...ON表达式中引用时,e1还不存在。

在我研究 Hibernate 时请稍候,看看你是否可以说服它JOIN在所有情况下都使用。


唔。Hibernate.org 上的所有内容似乎都重定向到了 jboss.org。所以现在无法在线阅读 HQL 文档。我相信他们最终会弄清楚他们的名字。

于 2009-04-17T18:18:31.443 回答
1

这可能有点跑题了,因为它根本不涉及休眠,但比尔卡尔文的评论真的让我大开眼界。您需要先进行显式连接,而不是先编写隐式连接。如果您有多个隐式连接,则此语法特别有趣。

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

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
于 2013-03-22T13:01:30.083 回答
0

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 JOIN b ON a.a_id = b.a_id JOIN c ON c.b_id = b.b_id AND c.a_id = a.a_id" 是允许的。

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

于 2009-04-17T18:19:31.643 回答