[AWS IoT Core] ルールSQLに追加された、SET句 と get_or_default()関数 で何が嬉しいかを試してみました
1 はじめに
製造ビジネステクノロジー部の平内(SIN)です。
2025年11月21日、AWS IoT CoreのルールSQLに、SET句による変数設定と、get_or_default()関数によるエラー処理が追加されました。
今までのIoT ルールSQLでは、同じ計算式を繰り返し記述する必要があったり、エラー発生でルールが動作しなくなる問題がありました。今回の機能追加で、いくつかの問題に対処できそうなので、少し試してみました。
2 SET句
SET句は、IoT ルールSQL内で変数を定義できる機能です。
SET @variable_name = expression
SET句があることで次のようなメリットがあります。
- 意味のある変数名で、複雑な式をわかりやすく書ける
- 同じ計算式を複数箇所に書く必要がなくなる
- timestamp()のような関数の値を定数化できる
制限は、以下です。

実装例
例1 DRY原則
電圧値からバッテリー残量パーセントを計算し、残量が50%未満のデータを抽出します。
入力JSON例:
{"device_id": "sensor-001", "voltage": 3.6}
SET句導入後:
SET @battery_percent = (voltage - 3.0) / (4.2 - 3.0) * 100
SELECT device_id,
@battery_percent as battery_percent
FROM 'sensors/battery'
WHERE @battery_percent < 50
SET句導入前:
SELECT device_id,
(voltage - 3.0) / (4.2 - 3.0) * 100 as battery_percent
FROM 'sensors/battery'
WHERE ((voltage - 3.0) / (4.2 - 3.0) * 100) < 50

バッテリー残量の計算式が1箇所になり、DRY原則に従えるようになりました。
例2 timestamp()
センサーから送られた時刻と現在時刻の差を計算し、遅延があるデータを検出します。
入力JSON例:
{"device_id": "sensor-001", "sensor_timestamp": 1700000000}
SET句導入後:
SET @current_time = timestamp(),
@delay_ms = @current_time - sensor_timestamp
SELECT device_id, @current_time as current_time, @delay_ms as delay_ms
FROM 'sensors/data'
WHERE @delay_ms > 5000

SET句導入前:
-- timestamp()を複数回呼び出すと値が一致しない可能性がある
SELECT device_id,
timestamp() as current_time, -- 1回目のtimestamp()
timestamp() - sensor_timestamp as delay_ms -- 2回目のtimestamp()
FROM 'sensors/data'
WHERE (timestamp() - sensor_timestamp) > 5000 -- 3回目のtimestamp()
-- current_time、delay_ms、WHERE条件でそれぞれ異なる値になる可能性がある
SET句がないと、timestamp()を複数回呼び出すことになり、SELECT句とWHERE句で微妙に値がずれる可能性があります。この例では、current_timeに記録される値、delay_msの計算に使われる値、WHERE句で判定に使われる値がすべて異なるタイミングで取得される可能性があり、正確な処理が困難でした。
3 get_or_default()
get_or_default()関数は、式の評価でエラーが発生した場合にデフォルト値を返す関数です。
基本構文:
get_or_default(expression, default_value)
get_or_default()関数を使うと以下のような利点があります。
- エラーが発生時にルール全体が停止しない
- エラー発生時も記録できる(デフォルト値で処理)
以下のような、注意がが、ドキュメントに記載されておりました。


get_or_default()関数の実装例
こちらもいくつか使用例を見てみます。
例1 フィールドの欠落
オプショナルなフィールドに安全にアクセスし、フィールドが存在しない場合もデフォルト値で処理を継続します。
入力JSON例(正常):
{"device_id": "sensor-001", "temperature": 25.5, "humidity": 60}
入力JSON例(フィールド欠落):
{"device_id": "sensor-002", "temperature": 22.0}
get_or_default()導入後:
SET @temperature = get_or_default(temperature, -999.0),
@humidity = get_or_default(humidity, -999.0)
SELECT device_id,
@temperature as temperature,
@humidity as humidity
FROM 'sensors/data'

get_or_default()導入前:
-- humidityフィールドが存在しない場合、ルール全体が失敗する
SELECT device_id,
temperature,
humidity
FROM 'sensors/data'

humidityフィールドが欠落している場合は-999.0というデフォルト値が設定されるため、ルールが止まらずにすべてのメッセージを処理できるようになります。
例2 型変換ミス
文字列型のデータを数値型に変換し、変換失敗は、デフォルト値で処理されます。
入力JSON例:
{
"device_id": "sensor-001",
"temperature_str": "25.5",
"humidity_str": "60",
"invalid_str": "NOT_A_NUMBER"
}
get_or_default()導入後:
SET @temperature = get_or_default(cast(temperature_str as Decimal), -999.0),
@humidity = get_or_default(cast(humidity_str as Decimal), -999.0),
@invalid_num = get_or_default(cast(invalid_str as Decimal), -999.0)
SELECT device_id,
@temperature as temperature,
@humidity as humidity,
@invalid_num as invalid_num
FROM 'sensors/strings'

get_or_default()導入前:
-- 型変換エラーでルール全体が失敗
SELECT device_id,
cast(temperature_str as Decimal) as temperature,
cast(humidity_str as Decimal) as humidity,
cast(invalid_str as Decimal) as invalid_num
FROM 'sensors/strings'

不正な値は、デフォルト値で記録されます。
4 組み合わせ
SET句とget_or_default()関数は一緒に使うと更に気持ちよく書けそうです。
入力JSON例:
{
"temperature": 25.5,
"humidity": 60
}
SET @temperature = get_or_default(temperature, -999.0),
@humidity = get_or_default(humidity, -999.0),
@comfort_index = (@temperature * 0.7) + (@humidity * 0.3)
SELECT device_id,
@temperature as temperature,
@humidity as humidity,
@comfort_index as comfort_index
FROM 'sensors/data'

5 最後に
AWS IoT CoreのルールSQLに追加されたSET句とget_or_default()関数を試してみました。
SET句は、計算式の重複を減らして可読性を上げるのに役立ちます。特にtimestamp()のような関数を複数箇所で使う場合、値の一貫性が保証されるのが素晴らしいと思います。
get_or_default()関数は、エラーハンドリングを簡単にしてくれます。フィールド欠落や型変換エラーでルール全体が止まることがなくなるので、システムの堅牢性が上がりそうです。
個人的には、ちょっとルールSQLを書くのが楽しくなりそうです。







