代替のデータ型
Data Shaping Query Languageでは、Avroスキーマを使い、同じエレメントに対して複数のデータ型を扱うことができます。
Avroスキーマの詳細は、Oracleのドキュメンテーションをご覧ください。
次のサンプルJSON入力では、order_amountというエレメントは次のいずれかとなります:
- 整数
- 10進数
- 文字列
- 2つの小数値(items_totalとtax_amount)が含まれているレコード
{
"orders": [
{
"order_id": "abc-12345",
"order_amount": 250
},
{
"order_id": "def-67890",
"order_amount": "299.99"
},
{
"order_id": "ghi-54321",
"order_amount": 435.95
},
{
"order_id": "jkl-09876",
"order_amount": {
"items_total": 395.99,
"tax_amount": 11.89
}
}
]
}
この入力は次のAvroスキーマで記述されます:
{
"type": "record",
"name": "root",
"fields": [
{
"name": "orders",
"type": {
"type": "array",
"items": {
"type": "record",
"name": "order",
"fields": [
{
"name": "order_id",
"type": "string"
},
{
"name": "order_amount",
"type": [
"int",
{
"type": "bytes",
"logicalType": "decimal"
},
"string",
{
"type": "record",
"name": "amount",
"fields": [
{
"name": "items_total",
"type": {
"type": "bytes",
"logicalType": "decimal"
}
},
{
"name": "tax_amount",
"type": {
"type": "bytes",
"logicalType": "decimal"
}
}
]
}
]
}
]
}
}
}
]
}
Data Shaping Query Languageでは、identifier.@indexという構文を使い、エレメントの識別子に型のインデックスを付加することで、それぞれの可能な型を参照できます。この例では、intはorder_amountエレメントで可能な型のリストの最初の値なので、order_amount.@0で参照できます。
この構文は階層識別子でも使用できます。たとえば、order_amount.@3.tax_amountを使ってレコード内のtax_amountエレメントを参照できます。
resolveChoiceファンクションを使用すれば、それぞれの反復やエレメントに使用される型を識別できます。このファンクションの詳細は、特別ファンクションをご覧ください。
この例では、次のクエリーを使い、orders配列の各項目でorder_amountエレメントに使用されているデータ型を取得できます:
FROM orders
SELECT {
order_id,
amount = resolveChoice(order_amount)
}
このクエリーは次の結果を返します:
[
{
"order_id": "abc-12345",
"amount_type": 0
},
{
"order_id": "def-67890",
"amount_type": 2
},
{
"order_id": "ghi-54321",
"amount_type": 1
},
{
"order_id": "jkl-09876",
"amount_type": 3
}
]
次に、データを調整し、order_amountエレメントで単一のデータ型を返すクエリーを書くことができます。たとえば次のクエリーを使用できます:
- スイッチ式とresolveChoiceファンクションを使って、それぞれの代替インデックスにデータ型を割り当てます。
- toDecimalファンクションを使って、文字列と整数値を小数に変換します。
- items_totalにtax_amountを加え、各レコードの合計金額を計算します。
FROM orders
LET $amount_type =
SWITCH (resolveChoice(order_amount)) {
CASE 0: 'INT'
CASE 1: 'DECIMAL'
CASE 2: 'STRING'
CASE 3: 'RECORD'
}
SELECT {
order_id,
amount =
IF ($amount_type = "STRING" OR $amount_type = "INT")
toDecimal(order_amount)
ELSEIF ($amount_type = "RECORD")
order_amount.@3.items_total + order_amount.@3.tax_amount
ELSE order_amount
}
このクエリーでは、order_amountの反復はそれぞれ入力タイプに関係なく10進値に変換されます。以下の結果が返されます:
[
{
"order_id": "abc-12345",
"amount": 250
},
{
"order_id": "def-67890",
"amount": 299.99
},
{
"order_id": "ghi-54321",
"amount": 435.95
},
{
"order_id": "jkl-09876",
"amount": 407.88
}
]