この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:5
ページ更新者:atom
更新日時:2026-06-11 07:12:00

タイトル: net.sf.hibernate.QueryException: unexpected token: as [~]
SEOタイトル: Hibernate「unexpected token: as」HQL 予約語衝突の原因と対処

この記事の要点
  • Hibernate / JPA で unexpected token: as は HQL / JPQL のパース失敗
  • 主因は SQL 予約語(user / order / group など)をテーブル名・カラム名にしている、または HQL なのにテーブル名で書いている
  • HQL は エンティティ参照FROM user_table u ではなく FROM User u
  • 対処: @Table(name="user") / @Column(name="order") でマッピング、HQL ではエンティティ名を使う
  • AS の使い所も限定的: SELECT 句のエイリアスFROM のエンティティエイリアスのみ
  • 回避不能なら createNativeQuery() でネイティブ SQL に切替(バックティック等で予約語をエスケープ)

このエラーの典型

Hibernate / JPA でクエリ実行時に次のような例外が出ます:

org.hibernate.QueryException: unexpected token: as [SELECT u FROM user as u]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(...)
    at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(...)
    ...
Caused by: NoViableAltException(...)

# 旧 net.sf.hibernate 系
net.sf.hibernate.QueryException: unexpected token: as [from order o where o.id = ?]

HQL / JPQL の文法的に as というトークンが想定外の位置に出てきた、という意味です。

原因 1: HQL でテーブル名を直接書いている

HQL は エンティティクラス参照で書きます。SQL のようにテーブル名で書くと、Hibernate は「エンティティが見つからない → 予約語? → パース失敗」となります。

// ❌ NG: テーブル名で書いている
String hql = "SELECT u FROM user_table as u WHERE u.id = :id";
Query q = em.createQuery(hql);

// ✅ OK: エンティティ名で書く
String jpql = "SELECT u FROM User u WHERE u.id = :id";
Query q = em.createQuery(jpql, User.class);

// エンティティ定義側
@Entity
@Table(name = "user_table")  // DB 上のテーブル名
public class User {
    @Id
    @Column(name = "user_id")
    private Long id;
}

原因 2: 予約語が含まれている

テーブル名・カラム名が user / order / group / desc / key のような SQL 予約語の場合、Hibernate は HQL → SQL 変換時にエスケープせず生成し、結果として unexpected tokenSQLGrammarException が起きます。

予約語の例使ってしまうと起きる現象
userPostgreSQL で syntax error at or near "user"
orderORDER BY と被って unexpected token
groupGROUP BY と衝突
desc / ascソート方向と衝突
key / typeMySQL で You have an error in your SQL syntax

対処 1: @Table / @Column でエスケープ

@Entity
@Table(name = "`order`")          // MySQL バックティック
// @Table(name = "\"order\"")     // PostgreSQL ダブルクォート
public class OrderEntity {

    @Id
    @Column(name = "order_id")
    private Long id;

    @Column(name = "`group`")     // カラム名も予約語ならエスケープ
    private String group;
}

// Hibernate 標準のエスケープ記法(DB ベンダー非依存)
@Table(name = "\"order\"")        // Hibernate が DB に応じて変換

application.properties で 常にエスケープさせる設定もあります:

# Spring Boot
spring.jpa.properties.hibernate.globally_quoted_identifiers=true

# Hibernate 直設定
hibernate.globally_quoted_identifiers=true

対処 2: HQL の AS の正しい使い方

HQL / JPQL で AS が許される位置は限定的です:

// ✅ エンティティのエイリアス(AS は省略可)
"FROM User AS u"
"FROM User u"          // 同じ意味

// ✅ SELECT 句のカラムエイリアス
"SELECT u.name AS userName FROM User u"

// ❌ NG: JOIN の ON にカラムエイリアスを書く
"SELECT u FROM User u JOIN Order AS o ON u.id = o.userId"
// → JPQL 2.1 以降は JOIN ... ON 自体は OK だが、エイリアス位置に注意

// ❌ NG: テーブル名で書く
"FROM user_table AS u"

対処 3: ネイティブ SQL に逃がす

どうしても複雑な SQL を書きたい場合は createNativeQuery() でネイティブ SQL を使い、結果を Entity マッピングします:

@PersistenceContext
EntityManager em;

// ネイティブ SQL
List<User> users = em.createNativeQuery(
    "SELECT * FROM `user` WHERE created_at > ?1",
    User.class
).setParameter(1, since).getResultList();

// Spring Data JPA でも @Query(nativeQuery = true)
public interface UserRepository extends JpaRepository<User, Long> {
    @Query(value = "SELECT * FROM `user` WHERE created_at > ?1", nativeQuery = true)
    List<User> findRecent(LocalDateTime since);
}

デバッグの定石

# application.properties で実 SQL を出力
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

実際に投げられる SQL を見れば、予約語エスケープ漏れか HQL の文法ミスかすぐ判別できます。

FAQ

Q: 旧 net.sf.hibernate と現在の org.hibernate で違いは?
A: net.sf.hibernate は Hibernate 2 系(2006 以前)。基本同じ問題ですが、新規プロジェクトは Hibernate 6.x + JPA 標準を推奨。

Q: @Table の name に予約語を入れたくない
A: テーブル名を app_user / orders に変える DB 設計が王道です。

Q: JPQL と HQL は同じ?
A: JPQL は仕様、HQL は Hibernate 独自拡張。基本構文は共通で、HQL の方が機能が広い(WITH 句等)。