「同じクエリなのに、結果が違う」
日付を整数で管理している現場では、こんなクエリをよく書く。
SELECT ( 20250515 / 100 ) <= 20250520250515(yyyymmdd形式の日付)を 100 で割って月(yyyymm)に変換し、202505 と比較する。
一見シンプルな式だ。
ところがこのクエリ、実行するSQLエンジンによって結果が変わる。
| エンジン | 結果 |
|---|---|
| Hive | false |
| Trino | true |
「バグか?」と焦るが、バグではない。
整数どうしの除算(/)に対する型の扱いが、エンジンごとに根本的に異なるからだ。
なぜ結果が変わるのか
答えはシンプルで、20250515 / 100 の計算結果の型が違う。
Hive の場合:浮動小数点除算
Hive は整数どうしの / を DOUBLE(浮動小数点数)として計算する。
20250515 / 100 = 202505.15 (DOUBLE)
その結果と 202505(INTEGER)を比較すると、
202505.15 <= 202505 → false
202505.15 は 202505 より大きいので、false になる。
Trino の場合:整数除算(切り捨て)
Trino は整数どうしの / を INTEGER として計算し、小数点以下を切り捨てる。
20250515 / 100 = 202505 (INTEGER、余り切り捨て)
その結果と 202505(INTEGER)を比較すると、
202505 <= 202505 → true
同じ値どうしの比較になるので、true になる。
まとめると
| エンジン | 20250515 / 100 の結果 | 型 | <= 202505 の評価 |
|---|---|---|---|
| Hive | 202505.15 | DOUBLE | false |
| Trino | 202505 | INTEGER | true |
仕様として正しいか
どちらが「間違い」ということはなく、SQL標準の解釈の違いだ。
ANSI SQL は整数どうしの除算について厳密な規定を設けておらず、実装に委ねている部分がある。Hive は BigQuery に近い「精度を失わない」方向の実装、Trino(旧 PrestoSQL)は多くのプログラミング言語(Python, Java, C など)と同じ「整数除算は整数で返す」方向の実装をとっている。
どちらが直感に近いかは人によるが、実務で引っかかりやすいのは確かだ。
実務でよく踏む場面
この挙動が問題になるのは、日付を整数で持っているテーブルで「日付 → 月」に変換するときだ。
SELECT *
FROM orders
WHERE ( order_date_int / 100 ) <= 202505Hive ベースの Treasure Data でこれを実行すると、order_date_int / 100 は DOUBLE になる。
整数で持つ月(202505)との比較は微妙にずれるため、意図通りに絞り込めないことがある。
安全な書き方:CAST で型を明示する
エンジンに依存しない書き方にするには、CAST で明示的に整数に変換してから比較する。
-- 安全な書き方(Hive / Trino 共通)
SELECT ( CAST( 20250515 AS BIGINT ) / 100 ) <= 202505CAST( 20250515 AS BIGINT ) / 100 は Hive でも Trino でも整数除算になり、結果は 202505(INTEGER)になる。
202505 <= 202505 → true (両エンジン共通)
あるいは、そもそも除算で月変換するのをやめて、文字列操作や専用の日付関数を使う方法もある。
-- 文字列 LEFT で月部分を切り出す(Hive / Trino 共通)
SELECT LEFT( CAST( 20250515 AS VARCHAR ), 6 ) -- '202505'
-- TD_TIME_FORMAT を使う(Treasure Data 環境)
SELECT TD_TIME_FORMAT( TD_DATE_TRUNC( 'month', time ), 'yyyyMM', 'JST' )Treasure Data(Hive/Trino 混在環境)での注意点
同じクエリを Hive と Trino で使い回している場合、このような型の挙動の違いでサイレントに結果が変わるリスクがある。
特に次のようなケースで踏みやすい。
- 日付を
yyyymmddの整数で持つテーブルを/100で月変換しているとき - セグメント条件に
INT列 / Nの比較を使っているとき - Hive で書いたクエリを Trino に移行したとき
移行時は、数値リテラルどうしの除算が含まれる箇所を優先的に確認することを勧める。
まとめ
| 確認ポイント | Hive | Trino |
|---|---|---|
整数 / 整数 の型 | DOUBLE(浮動小数点) | INTEGER(切り捨て) |
20250515 / 100 の値 | 202505.15 | 202505 |
<= 202505 の評価 | false | true |
| 安全な対処法 | CAST で整数に変換 | CAST で整数に変換 |
同じ SQL が異なるエンジンでサイレントに違う結果を返すのは、デバッグが難しいバグの温床になる。
整数除算を使うときは CAST で型を明示し、エンジンに依存しないクエリを書く習慣をつけておこう。