混合隐式和显式 JOIN

发布于 2024-07-16 16:58:30 字数 1649 浏览 5 评论 0原文

我遇到 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

这两个查询都有效。 我意识到存在笛卡尔积; 这是故意的。

显式 JOIN:

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

隐式 JOIN:

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 子句”中。

问题

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

I am having a problem with Hibernate generating invalid SQL. Specifically, mixing and matching implicit and explicit joins. This seems to be an open bug.

However, I'm not sure why this is invalid SQL. I have come up with a small toy example that generates the same syntax exception.

Schema

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

Data

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

Working SQL

Both of these queries work. I realize there is a Cartesian product; that's intentional.

Explicit JOIN:

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

Implicit JOIN:

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

Invalid SQL

This query does NOT work on MSSQL 2000/2008 or MySQL:

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

In MS2000, I get the error:

The column prefix 'e1' does not match
with a table name or alias name used
in the query.

In MySQL, the error is:

Unknown column 'e1.managerEmployeeID'
in 'on clause'.

Question(s)

  1. Why is this syntax invalid?
  2. Bonus: Is there a way to force Hibernate to use only explicit JOINs?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬シ愛 2024-07-23 16:58:30

这会导致错误,因为根据 SQL 标准,JOIN 关键字的优先级高于逗号。 棘手的一点是,只有在 FROM 子句中计算相应的表之后,表别名才可用。

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

当我研究 Hibernate 时,请耐心等待,看看您是否可以说服它在所有情况下都使用 JOIN


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

It results in an error because according to the SQL standard, the JOIN keyword has higher precedence than the comma. The sticky point is that table aliases are not usable until after the corresponding table has been evaluated in the FROM clause.

So when you reference e1 in your JOIN...ON expression, e1 doesn't exist yet.

Please stand by while I research Hibernate and find out if you can persuade it to use JOIN in all cases.


Hmm. Everything at Hibernate.org seems to be redirecting to jboss.org. So no way to read HQL documentation online right now. I'm sure they'll figure out their name serving eventually.

究竟谁懂我的在乎 2024-07-23 16:58:30

这可能有点偏离主题,因为它根本不涉及休眠,但来自 Bill Karwin 的评论真的让我大开眼界。 您需要先执行显式连接,而不是先编写隐式连接。 如果您有多个隐式连接,则此语法特别有趣。

检查 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

This might be a bit off topic, because it doesn't concern hibernate at all, but the comment from Bill Karwin really opened my eyes. Instead of writing the implicit joining first, you need to do the explicit joining first. This syntax is especially interesting if you have multiple implicit joins.

Check the following example in MS SQL. Not all contacts have a country code defined, but all contacts have an attribute val which will be looked up in the table Tbl. So the intuitive solution will not work:

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

Instead you might rather want to use the following syntax:

SELECT * FROM 
contacts LEFT OUTER JOIN country ON CtryCod = country.CtryCod, 
Tbl
WHERE val = Tbl.val
风筝在阴天搁浅。 2024-07-23 16:58:30

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”?

PostgreSQL gives an error too:

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.

I think the problem is that when you join two tables a and b (e2 and e1Manager in this case) you can only reference those two tables in the "ON" clause. So you can reference e2 and e1Manager in this ON clause, but not e1.

I think this extends so that if you have a chain of "JOIN" statements, you can reference other tables in the same chain in "ON" clauses, but you can't cross a ",". So something like `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" is allowed.

What's the HQL you are using to produce this SQL? Something like "select e1.name, e2.name, e1.manager.name from Employee e1, Employee e2" ?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文