例: JSONデータの更新

JSONデータは、JSON MERGE句またはADD句を使用して更新できます。

JSON MERGE句

JSON MERGE句を使用すると、JSONドキュメントに対する一連の変更を行うことができます。次の項の例では、CREATE TABLEトピックのエアライン手荷物追跡アプリケーションおよびストリーミング・メディア・サービス・アプリケーションについて考えてみます。

例7-33 既存のフィールドの更新およびJSONドキュメントへの新しいフィールドの追加

UPDATE BaggageInfo b 
JSON MERGE b.bagInfo[0] WITH PATCH {"tagNum" : "18657806255240", "routing" : "MIA/LAX", "lastSeenStation" : "LAX", "bagStatus" : "delivered"}
WHERE ticketNo = 1762344493810 RETURNING b.bagInfo[0].tagNum, b.bagInfo[0].routing, b.bagInfo[0].lastSeenStation, b.bagInfo[0].bagStatus

説明: 前述の問合せで、航空会社手荷物追跡アプリケーションの乗客のレコードを更新して、いくつかの不注意なエラーを修正しました。JSON MERGE句は、パッチの内容を現在の内容と比較し、bagInfo JSON配列の最初の要素のtagNumroutingおよびlastSeenStationフィールドを更新します。bagStatusフィールドは現在、bagInfo配列の最初の要素の一部ではないため、JSON MERGEパッチはそれをドキュメントに挿入します。

更新されたフィールドのみを表示するには、RETURNING句を指定してUPDATE文を使用します。

出力:
{
  "tagNum" : "18657806255240",
  "routing" : "MIA/LAX",
  "lastSeenStation" : "LAX",
  "bagStatus" : "delivered"
}

ノート:

ここで、bagInfoはJSONドキュメントの配列で、乗客ごとの受託手荷物を表します。更新する配列要素を指定しない場合、JSON MERGE句によって、bagInfo配列全体がパッチの内容に置き換えられます。1人の乗客に複数の受託手荷物がある場合は、次のように同じUPDATE文でJSON MERGE句を繰り返し使用できます:
UPDATE BaggageInfo b 
JSON MERGE b.bagInfo[0] WITH PATCH {"tagNum" : "18657806255111", "routing" : "MIA/LAX", "lastSeenStation" : "LAX", "bagStatus" : "delivered"},
JSON MERGE b.bagInfo[1] WITH PATCH {"tagNum" : "18657806255112", "routing" : "MIA/LAX", "lastSeenStation" : "LAX", "bagStatus" : "delivered"}
WHERE ticketNo = 1762320369957

例7-34 パッチにJSONパスを使用した新しいフィールドの追加

航空会社の手荷物追跡アプリケーションの次の乗客のデータについて考えてみます。ネストされたflightLegsドキュメントには、フライト番号は含まれていません。

{"ticketNo":1882344493810,"fullName":"Joan Smith","gender":"F","contactPhone":"886-324-1064","confNo":"LE6F4Z","bagInfo":[{"flightLegs":{"estimatedArrival":"2019-02-01T11:00:00Z","flightDate":"2019-02-01T06:00:00Z","fltRouteDest":"LAX","fltRouteSrc":"MIA"},"id":"79039899165297","routing":"MIA/LAX","tagNum":"17657806255240"}]}

次のように、flightNoフィールドをflightLegsドキュメントに含めるパッチを適用できます:

UPDATE BaggageInfo b
JSON MERGE b.bagInfo[0] WITH PATCH {"flightLegs": {"flightNo":"BM107"}} WHERE ticketNo = 1882344493810 RETURNING *

説明: ここで、パッチ式にflightNoフィールドのJSONパスを指定します。JSON MERGE句は、JSONパスを評価し、bagInfo配列の最初の要素のネストされたflightLegsドキュメントにflightNoフィールドを挿入します。

出力:

{"ticketNo":1882344493810,"fullName":"Joan Smith","gender":"F","contactPhone":"886-324-1064","confNo":"LE6F4Z","bagInfo":[{"flightLegs":{"estimatedArrival":"2019-02-01T11:00:00Z","flightDate":"2019-02-01T06:00:00Z","flightNo":"BM107","fltRouteDest":"LAX","fltRouteSrc":"MIA"},"id":"79039899165297","routing":"MIA/LAX","tagNum":"17657806255240"}]}

ノート:

ネストされたflightLegsドキュメントが存在しない場合、JSON MERGEパッチによって作成されます。

例7-35 JSONドキュメントからのフィールドの削除およびネストされたドキュメントの挿入

UPDATE stream_acct s
JSON MERGE s.acct_data WITH PATCH {"country" : NULL, "recommended" : {"showName1" : "laugh it", "showName2": "Mystery solved", "showName3": "bakesnCooks"}}
WHERE acct_id = 1 RETURNING *

説明: 前述の問合せでは、JSON MERGE句を使用して、ストリーミング・メディア・サービス・アプリケーションのサブスクライバ・レコードを更新しています。パッチ式で、countryおよびrecommendedフィールドを指定します。JSON MERGEパッチは、新しいネストされたrecommended JSONドキュメントをacct_data JSONドキュメントに挿入します。NULL値を指定して、ドキュメントからcountryフィールドを削除することを示します。

RETURNING句は、更新された行全体をフェッチします。

出力:

{
  "acct_id" : 1,
  "profile_name" : "AP",
  "account_expiry" : "2023-10-18T00:00:00.000000000Z",
  "acct_data" : {
    "contentStreamed" : [{
      "genres" : ["action", "crime", "spanish"],
      "numSeasons" : 4,
      "seriesInfo" : [{
        "episodes" : [{  .... }],
      "showId" : 26,
      "showName" : "At the Ranch",
      "showtype" : "tvseries"
    }, {
      "genres" : ["comedy", "french"],
      "numSeasons" : 2,
      "seriesInfo" : [{
        "episodes" : [{ .... }],

      "showId" : 15,
      "showName" : "Bienvenu",
      "showtype" : "tvseries"
    }],
    "firstName" : "Adam",
    "lastName" : "Phillips",
    "recommended" : {
      "showName1" : "laugh it",
      "showName2" : "Mystery solved",
      "showName3" : "bakesnCooks"
    }
  }
}

例7-36 ドキュメントのフィールドの更新/追加

ストリーミング・メディア・サービス・アプリケーションからの次のサブスクライバ・レコードについて考えてみましょう。

{"acct_id":1,"profile_name":"AP","account_expiry":"2023-10-18T00:00:00.000000000Z","acct_data":{"contentStreamed":[{"genres":["action","crime","spanish"],"numSeasons":4,"showId":26,"showName":"At the Ranch","showtype":"tvseries"},{"genres":["comedy","french"],"numSeasons":2,"showId":15,"showName":"Bienvenu","showtype":"tvseries"}],"firstName":"Adam","lastName":"Phillips"}}

{"acct_id":2,"profile_name":"AW","account_expiry":"2025-12-18T00:00:00.000000000Z","acct_data":{"contentStreamed":{"genres":["comedy","french"],"numSeasons":2,"showId":15,"showName":"Bienvenu","showtype":"tvseries"},"country":"France","firstName":"Adelaide","lastName":"Willard"}}

例4a: JSON MERGE句を使用して、前述のレコードのacct_data JSONドキュメントのcountryフィールドを更新します。

UPDATE stream_acct s
JSON MERGE s.acct_data WITH PATCH { "country" : "USA"} WHERE acct_id = 1 RETURNING s.acct_id, s.acct_data.country

UPDATE stream_acct s
JSON MERGE s.acct_data WITH PATCH { "country" : "Italy"} WHERE acct_id = 2 RETURNING s.acct_id, s.acct_data.country

説明: acct_id 1に対する最初のUPDATE文では、元のドキュメントにcountryフィールドが存在しないため、JSON MERGE句はcountryフィールドをacct_data JSONドキュメントに挿入します。2番目のUPDATE文では、JSON MERGE句によって、サブスクライバacct_id 2のcountryフィールド値がFranceからItalyに更新されます。

出力:

{"acct_id":1,"country":"USA"}
1 row returned

{"acct_id":2,"country":"Italy"}
1 row returned

例4b: パス式を使用してcountryフィールドを更新します。

ストリーミング・メディア・サービス・アプリケーションの元のサブスクライバ・レコードについて考えてみましょう。

acct_id 2のレコードのパス式を使用して、countryフィールドを更新します。

UPDATE stream_acct s
JSON MERGE s.acct_data.country WITH PATCH "Switzerland" where acct_id = 2

{"NumRowsUpdated":1}

説明: UPDATE操作が成功し、countryフィールド値が指定された値に置き換えられました。次に、acct_id 1のサブスクライバ・レコードを更新します。

UPDATE stream_acct s
JSON MERGE s.acct_data.country WITH PATCH "USA" where acct_id = 1

{"NumRowsUpdated":0}

例4aのcountryフィールドが正常に挿入されたacct_id 1のUPDATE操作とは対照的に、ここでは何も処理を行いません。パス式を使用して直接アクセスされるフィールドがターゲットJSONドキュメントに存在しない場合、結果のJSON MERGE操作では何も処理を行いません。

例7-37 JSONのNULLフィールドの更新

ストリーミング・メディア・サービス・アプリケーションからの次のサブスクライバ・レコードについて考えてみましょう。

{"acct_id":1,"profile_name":"AP","account_expiry":"2023-10-18T00:00:00.000000000Z","acct_data":null}

ここで、acct_dataはNULL値を持つJSONフィールドです。JSON MERGE句を使用してフィールドを更新します。

JSON MERGE s.acct_data WITH PATCH {"contentStreamed":{"genres":["comedy","french"],"numSeasons":2,"showId":15,"showName":"Bienvenu","showtype":"tvseries"},"country":NULL,"firstName":"Adam","lastName":"null"} WHERE acct_id = 1 RETURNING *

説明: JSON MERGEパッチは、acct_dataドキュメントのNULL値を、パッチ式から指定されたJSON値に置き換えます。countryフィールドにJSONのNULL値を指定しています。JSON MERGEパッチは、このフィールドをacct_dataドキュメントに挿入しません。ただし、文字列値nulllastNameフィールドは正常に挿入されます。

出力:

{"acct_id":1,"profile_name":"AP","account_expiry":"2023-10-18T00:00:00.000000000Z","acct_data":{"contentStreamed":{"genres":["comedy","french"],"numSeasons":2,"showId":15,"showName":"Bienvenu","showtype":"tvseries"},"firstName":"Adam","lastName":"null"}}

ADD句

ADD句を使用すると、JSONドキュメントのフィールドを更新できます。ADD句を使用して、1つ以上の配列要素を既存の配列に追加できます。オプションで、配列に追加する新しい要素の位置を指定することもできます。

例7-38 JSONデータの既存の配列への単一要素の追加

People表には、現在、次に示すように1つの行があります。表の作成とデータの挿入については、「例: 行の更新」を参照してください。
SELECT * FROM People

{
  "id" : 0,
  "info" : {
    "address" : {
      "city" : "Santa Cruz",
      "phones" : [{
        "areacode" : 831,
        "kind" : "mobile",
        "number" : 5294368
      }, {
        "areacode" : 650,
        "kind" : "mobile",
        "number" : 3789021
      }, {
        "areacode" : 415,
        "kind" : "home",
        "number" : 6096010
      }],
      "state" : "CA"
    },
    "children" : {
      "Anna" : {
        "age" : 11,
        "friends" : ["Anna", "John", "Maria", "Ada", "Aris"],
        "school" : "school_1"
      },
      "Mary" : {
        "age" : 8,
        "friends" : ["Anna", "Mark", "Ada", "Aris"],
        "school" : "school_3"
      },
      "Ron" : {
        "age" : 3,
        "friends" : ["Julie", "Ada", "Aris"]
      }
    },
    "firstName" : "John",
    "income" : 20000,
    "lastName" : "Doe",
    "profession" : "surfing instructor"
  }
}
配列の最初のほうにあるphones配列に新しい要素を追加します。
UPDATE People p ADD p.info.address.phones 0 
{"areacode":499, "number":33864368, "kind":"mobile" }
WHERE id = 0
SELECT * FROM People
出力:

{

  "id" : 0,
  "info" : {
    "address" : {
      "city" : "Santa Cruz",
      "phones" : [{
        "areacode" : 499,
        "kind" : "mobile",
        "number" : 33864368
      }, {
        "areacode" : 831,
        "kind" : "mobile",
        "number" : 5294368
      }, {
        "areacode" : 650,
        "kind" : "mobile",
        "number" : 3789021
      }, {
        "areacode" : 415,
        "kind" : "home",
        "number" : 6096010
      }],
      "state" : "CA"
    },
    "children" : {
      "Anna" : {
        "age" : 11,
        "friends" : ["Anna", "John", "Maria", "Ada", "Aris"],
        "school" : "school_1"
      },
      "Mary" : {
        "age" : 8,
        "friends" : ["Anna", "Mark", "Ada", "Aris"],
        "school" : "school_3"
      },
      "Ron" : {
        "age" : 3,
        "friends" : ["Julie", "Ada", "Aris"]
      }
    },
    "firstName" : "John",
    "income" : 20000,
    "lastName" : "Doe",
    "profession" : "surfing instructor"
  }
}

例7-39 JSONデータの既存の配列への要素の配列の追加

配列の複数の要素をJSONデータの既存の配列に追加する必要がある場合は、カッコ内に新しい要素の式を追加し、オプションで位置式(ある場合)を追加する必要があります。

次の問合せでは、次のようにエラーがスローされます。
UPDATE People p
ADD p.info.address.phones
0 { "areacode":5, "number":1, "kind":"mobile" },
  { "areacode":6, "number":2, "kind":"mobile" }
WHERE id = 0
出力:

Error handling command UPDATE People p
ADD p.info.address.phones
0 { "areacode":5, "number":1, "kind":"mobile" },
  { "areacode":6, "number":2, "kind":"mobile" }
WHERE id = 0:
Error: at (5, 12) mismatched input '<EOF>' expecting {WHERE, ','}, at line 5:12
rule stack: [parse, statement, update_statement]

これは、次に示すように、2つの異なるオプションのいずれかを使用して修正できます。

オプション1:
UPDATE People p
ADD p.info.address.phones  
([{ "areacode":1, "number":1, "kind":"mobile" },
  { "areacode":2, "number":2, "kind":"mobile" }
 ][])
WHERE id = 0
出力:

{
  "NumRowsUpdated" : 1
}
1 row returned
オプション2:
UPDATE People p
ADD p.info.address.phones
0 [{ "areacode":3, "number":1, "kind":"mobile" },
   {"areacode":4, "number":2, "kind":"mobile" }
  ]
WHERE id = 0
出力:

{
  "NumRowsUpdated" : 1
}
1 row returned
UPDATE文の結果は、次に示すように検証できます。
select * from People
出力:

{
  "id" : 0,
  "info" : {
    "address" : {
      "city" : "Santa Cruz",
      "phones" : [[{
        "areacode" : 3,
        "kind" : "mobile",
        "number" : 1
      }, {
        "areacode" : 4,
        "kind" : "mobile",
        "number" : 2
      }], {
        "areacode" : 499,
        "kind" : "mobile",
        "number" : 33864368
      }, {
        "areacode" : 831,
        "kind" : "mobile",
        "number" : 5294368
      }, {
        "areacode" : 650,
        "kind" : "mobile",
        "number" : 3789021
      }, {
        "areacode" : 415,
        "kind" : "home",
        "number" : 6096010
      }, {
        "areacode" : 1,
        "kind" : "mobile",
        "number" : 1
      }, {
        "areacode" : 2,
        "kind" : "mobile",
        "number" : 2
      }],
      "state" : "CA"
    },
    "children" : {
      "Anna" : {
        "age" : 11,
        "friends" : ["Anna", "John", "Maria", "Ada", "Aris"],
        "school" : "school_1"
      },
      "Mary" : {
        "age" : 8,
        "friends" : ["Anna", "Mark", "Ada", "Aris"],
        "school" : "school_3"
      },
      "Ron" : {
        "age" : 3,
        "friends" : ["Julie", "Ada", "Aris"]
      }
    },
    "firstName" : "John",
    "income" : 20000,
    "lastName" : "Doe",
    "profession" : "surfing instructor"
  }
}