diff --git a/README.md b/README.md index b381bfd..504acab 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1428 TILs and counting..._ +_1429 TILs and counting..._ --- @@ -611,6 +611,7 @@ _1428 TILs and counting..._ - [List Databases And Tables](mysql/list-databases-and-tables.md) - [Run Statements In A Transaction](mysql/run-statements-in-a-transaction.md) - [Select Rows After An Offset](mysql/select-rows-after-an-offset.md) +- [Set Value On Null JSON Column](mysql/set-value-on-null-json-column.md) - [Show Create Statement For A Table](mysql/show-create-statement-for-a-table.md) - [Show Tables That Match A Pattern](mysql/show-tables-that-match-a-pattern.md) - [Show Indexes For A Table](mysql/show-indexes-for-a-table.md) diff --git a/mysql/set-value-on-null-json-column.md b/mysql/set-value-on-null-json-column.md new file mode 100644 index 0000000..90b4c10 --- /dev/null +++ b/mysql/set-value-on-null-json-column.md @@ -0,0 +1,44 @@ +# Set Value On Null JSON Column + +To set a key-value pair on a JSON field, you can reach for +[MySQL's `json_set`](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-set) +or one of [the other JSON setter +functions](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html). + +However, if the JSON field you are updating is `null`, you might get an +unexpected result. + +```sql +> update User + set metadata = json_set(metadata, '$.discord_id', 'discord_123') + where id = 123; + +Query OK, 0 rows affected (0.00 sec) +Rows matched: 1 Changed: 0 Warnings: 0 +``` + +We can see that the `where` clause matched on a single row as expected, but +right above that it says _0 rows affected_. + +What happened? + +The `json_set` function is not able to set a key-value pair on `null`. It needs +a JSON object to work on. + +There are a number of ways to get around this. I find that +[`coalesce`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_coalesce) +is a natural way to handle this. If `metadata` happens to be `null`, then we +_coalesce_ it to `'{}'` (an empty object). + +```sql +> update User + set metadata = json_set(coalesce(metadata, '{}'), '$.discord_id', 'discord_123') + where id = 123; + +Query OK, 1 row affected (0.02 sec) +Rows matched: 1 Changed: 1 Warnings: 0 +``` + +It updates as expected. That same statement will work on a row where `metadata` +already contains a JSON object since the `coalesce` will resolve to that +instead of the empty object.