SQL JSON UPDATE 欄位值操作修改

學會了如何讀取 JSON 後,接下來我們要探討如何「動態產生」新的 JSON 文件,以及如何精確地更新已經儲存在資料庫中的 JSON 欄位。

動態建立 JSON 文件

在 SQL 中組裝 JSON 非常強大,因為你可以直接將資料表的欄位值「打包」成標準的 JSON 格式,這在產出 API 原始資料或進行資料遷移時非常實用。

JSON_OBJECT():建立物件

將「鍵 (Key)」與「值 (Value)」配搭成物件。鍵必須是字串,值可以是任何型態(包括另一個 JSON)。

SELECT JSON_OBJECT(
    'user_id', id, 
    'is_active', TRUE, 
    'login_at', NOW()
) AS user_json 
FROM users;

JSON_ARRAY():建立陣列

將一組值按順序封裝進陣列中。

SELECT JSON_ARRAY(name, email, age) FROM users;
-- 輸出範例: ["Mike", "mike@example.com", 25]

JSON 聚合函數:JSON_ARRAYAGG() 與 JSON_OBJECTAGG()

當你需要將「多列 (Multiple Rows)」資料合併成一個大的 JSON 陣列或物件時,這兩個彙總函數是利器。

-- 將所有產品名稱合併成一個 JSON 陣列
SELECT JSON_ARRAYAGG(name) FROM products;
-- 輸出: ["iPhone", "iPad", "MacBook"]

-- 將員工編號與姓名對應成一個大的 JSON 物件
SELECT JSON_OBJECTAGG(emp_id, emp_name) FROM employees;
-- 輸出: {"101": "張一", "102": "王二"}

修改既存 JSON 的三劍客

在執行 UPDATE 時,我們往往只想變更 JSON 中的某一小部分,而不是替換掉整塊資料。SQL 提供了三種邏輯截然不同的修改函數:

修改邏輯對照表

函數屬性存在時屬性不存在時適用場景
JSON_SET()更新新增最通用,不確定屬性是否已存在時使用
JSON_INSERT()無動作新增初次初始化屬性,避免覆寫舊資料
JSON_REPLACE()更新無動作僅更新已有資料,確保不產生多餘屬性

範例:靈活更新個人資訊

假設 profile 原本為 {"city": "Taipei"}

-- 使用 JSON_SET: 更新城市名並新增新屬性 'vocation'
UPDATE users 
SET profile = JSON_SET(profile, '$.city', 'Tainan', '$.vocation', 'Engineer')
WHERE id = 1;
-- 結果: {"city": "Tainan", "vocation": "Engineer"}

-- 使用 JSON_INSERT: 因為 'city' 已存在,它不會被改為 'London'
UPDATE users 
SET profile = JSON_INSERT(profile, '$.city', 'London', '$.hobby', 'Golf')
WHERE id = 1;
-- 結果: {"city": "Tainan", "vocation": "Engineer", "hobby": "Golf"}

陣列的高階操作

針對 JSON 陣列,我們不只有追加,還能指定位置插入。

JSON_ARRAY_APPEND()

在陣列的「末端」追加元素。如果路徑原本不是陣列,它會自動將原值與新值封裝成陣列。

-- 在 tags 陣列最後加入 "Sale"
UPDATE products 
SET tags = JSON_ARRAY_APPEND(tags, '$', 'Sale') 
WHERE id = 101;

JSON_ARRAY_INSERT()

在「指定索引位置」插入元素。與 APPEND 不同,它會將指定位置後的元素依序往後移。

-- 在第二個位置 (索引 1) 插入 "Featured"
UPDATE products 
SET tags = JSON_ARRAY_INSERT(tags, '$[1]', 'Featured') 
WHERE id = 101;

JSON_REMOVE() 刪除指定內容

可以用來刪除物件中的某個 Key,或是陣列中的某個位置。

-- 1. 刪除物件屬性
UPDATE users SET profile = JSON_REMOVE(profile, '$.vocation') WHERE id = 1;

-- 2. 刪除陣列第三個元素
UPDATE products SET tags = JSON_REMOVE(tags, '$[2]') WHERE id = 101;

合併 JSON 文件的差異

當你需要將兩塊 JSON 合併(例如把使用者的舊設定與新預設值合併)時,有兩種主要方式:

JSON_MERGE_PATCH() (推薦:RFC 7396)

邏輯:後者完全覆寫前者。 如果兩邊都有同名的 Key,且值不是物件,則由後面的值勝出。

SELECT JSON_MERGE_PATCH('{"a": 1, "b": 2}', '{"a": 9, "c": 3}');
-- 結果: {"a": 9, "b": 2, "c": 3}

JSON_MERGE_PRESERVE()

邏輯:保留所有資料。 如果兩邊都有同名的 Key,它會將兩者的值「合併成陣列」保留下來。

SELECT JSON_MERGE_PRESERVE('{"a": 1}', '{"a": 9}');
-- 結果: {"a": [1, 9]}
重要注意事項: 所有的 JSON 修改函數(如 JSON_SET)都不會直覺地修改資料快取。它們只是計算並回傳一個「處理後的 JSON 字串」。你必須依賴標準的 UPDATE 敘述,並將結果賦值給該欄位,改動才會真正存入硬碟。

透過這些靈活的建立與修改工具,你可以將 SQL 操作提升到類似 NoSQL 的開發效率。