Смешивание неявных и явных СОЕДИНЕНИЙ - PullRequest
8 голосов
/ 17 апреля 2009

У меня проблема с 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 ошибка:

Неизвестный столбец 'e1.managerEmployeeID' в «на оговорку».

Вопрос (ы)

  1. Почему этот синтаксис неверен?
  2. Бонус: Есть ли способ заставить Hibernate использовать только явные соединения?

Ответы [ 3 ]

13 голосов
/ 17 апреля 2009

Это приводит к ошибке, поскольку в соответствии со стандартом SQL ключевое слово JOIN имеет более высокий приоритет, чем запятая. Важным моментом является то, что псевдонимы таблиц нельзя использовать до тех пор, пока после соответствующая таблица не будет оценена в предложении FROM.

Поэтому, когда вы ссылаетесь на e1 в выражении JOIN...ON, e1 еще не существует.

Пожалуйста, подождите, пока я исследую Hibernate, и выясните, сможете ли вы убедить его использовать JOIN во всех случаях.


Хм. Все на Hibernate.org, кажется, перенаправляет на jboss.org. Так что сейчас нет возможности читать документацию по HQL онлайн. Я уверен, что со временем они выяснят свое имя.

0 голосов
/ 22 марта 2013

Это может быть немного не по теме, потому что это вообще не касается спящего режима, но комментарий Билла Карвина действительно открыл мне глаза. Вместо того, чтобы сначала писать неявное соединение, сначала нужно сделать явное соединение. Этот синтаксис особенно интересен, если у вас есть несколько неявных объединений.

Проверьте следующий пример в 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
0 голосов
/ 17 апреля 2009

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». Таким образом, вы можете ссылаться на e2 и e1Manager в этом предложении ON, но не на 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".

Какой HQL вы используете для создания этого SQL? Что-то вроде «выберите e1.name, e2.name, e1.manager.name из Employee e1, Employee e2»?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...