ทำความรู้จัก JSON ในโลกของฐานข้อมูล
เวลาเราเขียนโปรแกรม เรามักจะเจอข้อมูลที่หน้าตาแปลกๆ ที่ไม่ใช่ตารางเรียงกันสวยงาม ข้อมูลพวกนี้เรียกว่า JSON (รูปแบบการเก็บข้อมูลแบบข้อความที่อ่านง่าย) ซึ่งเปรียบเสมือนกล่องใส่ของที่ข้างในมีช่องเล็กช่องน้อยเก็บข้อมูลไว้เป็นชุดๆ ฐานข้อมูลอย่าง MS-SQL (โปรแกรมจัดการฐานข้อมูลของไมโครซอฟท์) จึงต้องมีวิธีจัดการกับข้อมูลแบบนี้เพื่อให้เราดึงไปใช้ได้ง่ายขึ้น
ลองนึกภาพว่าคุณกำลังเก็บข้อมูล "รายการสินค้า" ในฐานข้อมูลปกติ เราต้องแยกตารางชื่อสินค้า ตารางสี ตารางขนาด แต่ถ้าใช้ JSON เราสามารถเก็บข้อมูลทุกอย่างของสินค้านั้นไว้ในช่องเดียวได้เลย มันทำให้การออกแบบฐานข้อมูลยืดหยุ่นขึ้นมาก โดยเฉพาะเวลาเราทำ API (ช่องทางเชื่อมต่อเพื่อให้โปรแกรมคุยกันได้) ที่ต้องส่งข้อมูลไปให้หน้าเว็บหรือแอปมือถือ
การเข้าใจวิธีจัดการข้อมูลแบบนี้เป็นทักษะที่โปรแกรมเมอร์ยุคใหม่ต้องมี เพราะทุกวันนี้ข้อมูลส่วนใหญ่บนอินเทอร์เน็ตวิ่งไปมาในรูปแบบนี้ทั้งสิ้น หากเราดึงข้อมูลจากฐานข้อมูลออกมาเป็น JSON ได้โดยตรง เราก็ไม่ต้องเสียเวลาเขียนโค้ดแปลงข้อมูลเองในภาษาโปรแกรมให้ยุ่งยาก ทำให้งานเราเสร็จไวขึ้นและลดโอกาสเกิดบั๊ก (ข้อผิดพลาดในโปรแกรม) ได้อีกด้วย
แปลงข้อมูลจากตารางให้เป็น JSON ด้วย FOR JSON
สมมติว่าเรามีตารางชื่อ Products เก็บชื่อสินค้าและราคาไว้ เราอยากดึงข้อมูลนี้ออกไปให้แอปมือถือใช้งาน เราไม่จำเป็นต้องเขียนโค้ดวนลูปทีละแถวเพื่อสร้างไฟล์ JSON เอง แต่เราสามารถใช้คำสั่ง FOR JSON PATH ต่อท้ายคำสั่ง SELECT (คำสั่งดึงข้อมูล) เพื่อให้ฐานข้อมูลจัดหน้าตาข้อมูลออกมาให้เราเสร็จสรรพ
วิธีนี้ช่วยประหยัดเวลาได้มหาศาล เพราะฐานข้อมูลจะจัดการเรื่องการใส่เครื่องหมายปีกกาและคอมมาให้เราอัตโนมัติ เราแค่ต้องระบุว่าอยากได้รูปแบบไหนผ่านตัวเลือกอย่าง PATH (การกำหนดโครงสร้างข้อมูลตามชื่อคอลัมน์) หรือ AUTO (การสร้างรูปแบบข้อมูลตามโครงสร้างตาราง) ซึ่งแบบ PATH จะเป็นที่นิยมที่สุดเพราะปรับแต่งชื่อช่องได้อิสระ
จุดที่มือใหม่มักพลาดคือการลืมใส่เงื่อนไขให้ถูกต้อง ทำให้ข้อมูลออกมาเป็นก้อนใหญ่เกินไป หรือโครงสร้างไม่ตรงกับที่แอปต้องการ ดังนั้นก่อนใช้คำสั่งนี้ ให้ลอง SELECT ข้อมูลออกมาดูเป็นตารางปกติก่อนเสมอ เพื่อเช็คว่าเราเลือกคอลัมน์มาครบและถูกต้องตามที่ต้องการใช้งานจริงแล้วหรือยัง
-- ดึงข้อมูลสินค้าและแปลงเป็น JSON
SELECT
ID AS 'ProductID',
Name AS 'ProductName'
FROM Products
FOR JSON PATH;
-- คำสั่งนี้จะเปลี่ยนตารางให้เป็นข้อความ JSON
ในโค้ดนี้ SELECT คือการเลือกข้อมูล AS คือการตั้งชื่อใหม่ให้คอลัมน์เพื่อให้ชื่อใน JSON สวยงาม ส่วน FOR JSON PATH คือหัวใจหลักที่สั่งให้ฐานข้อมูลแปลงผลลัพธ์เป็นข้อความรูปแบบ JSON ทันที ผลลัพธ์ที่ได้จะเป็นข้อความหน้าตาแบบนี้: [{"ProductID":1,"ProductName":"Laptop"},{"ProductID":2,"ProductName":"Mouse"}]
ดึงค่าเฉพาะเจาะจงด้วย JSON_VALUE()
บางครั้งเรามีข้อมูล JSON ก้อนใหญ่เก็บอยู่ในตาราง แต่เราอยากได้แค่ค่าเดียว เช่น อยากรู้ว่า "สี" ของสินค้าคืออะไร เราไม่จำเป็นต้องดึงข้อมูลทั้งก้อนออกมาที่โปรแกรมแล้วค่อยมาแยกเอง แต่เราใช้ฟังก์ชัน JSON_VALUE() (คำสั่งดึงค่าเดี่ยวจากข้อมูล JSON) เพื่อหยิบแค่ค่าที่ต้องการออกมาจากฐานข้อมูลได้เลย
ลองจินตนาการว่าข้อมูล JSON คือตู้ล็อกเกอร์ที่มีเลขกำกับ เราแค่บอกเลขล็อกเกอร์ที่ต้องการ JSON_VALUE ก็จะไปหยิบของชิ้นนั้นมาให้เราทันที มันช่วยลดปริมาณข้อมูลที่ต้องส่งผ่านสายแลนหรืออินเทอร์เน็ตได้มาก เพราะเราดึงเฉพาะสิ่งที่จำเป็นต้องใช้จริงๆ ไม่ต้องขนข้อมูลขยะออกมาด้วย
ข้อควรระวังคือฟังก์ชันนี้จะส่งค่ากลับมาเป็นแบบข้อความ (Text) เท่านั้น ถ้าเราต้องการนำค่านั้นไปคำนวณทางคณิตศาสตร์ต่อ เราต้องทำการ Cast (การแปลงชนิดข้อมูล) ให้เป็นตัวเลขก่อนเสมอ ไม่อย่างนั้นโปรแกรมอาจจะฟ้องว่าข้อมูลไม่ตรงกันและทำงานไม่ได้
-- ดึงค่าเฉพาะจากข้อมูล JSON
SELECT JSON_VALUE(Details, '$.Color') AS ProductColor
FROM Products;
-- $ คือจุดเริ่มต้นของข้อมูล .Color คือตำแหน่งที่ต้องการ
คำสั่ง JSON_VALUE ทำหน้าที่เจาะเข้าไปในคอลัมน์ที่เก็บ JSON แล้วดึงค่าที่อยู่ในตำแหน่ง $.Color ออกมา ผลลัพธ์ที่ได้จะเป็นค่าเดี่ยวๆ เช่น "Red" หรือ "Blue" ตามที่เก็บไว้ในข้อมูลจริง
ดึงข้อมูลชุดใหญ่ด้วย JSON_QUERY()
ถ้าสิ่งที่เราต้องการไม่ใช่ค่าเดี่ยวๆ แต่เป็นข้อมูลชุดย่อย เช่น ข้อมูลที่อยู่ภายในก้อน JSON อีกที เราจะใช้ JSON_VALUE ไม่ได้ เพราะมันจะคืนค่าออกมาเป็นข้อความธรรมดา แต่เราต้องใช้ JSON_QUERY() (คำสั่งดึงข้อมูลชุดย่อยหรือออบเจกต์จาก JSON) แทน เพื่อให้ได้ข้อมูลที่ยังคงสภาพเป็น JSON อยู่
ตัวอย่างเช่น สินค้าหนึ่งชิ้นอาจมีข้อมูล "สเปก" เก็บเป็น JSON ก้อนเล็กๆ อยู่ข้างใน ถ้าเราอยากได้ข้อมูลสเปกนี้ไปส่งต่อให้ระบบอื่น JSON_QUERY จะรักษาโครงสร้างเดิมไว้ให้เรา ทำให้ระบบปลายทางอ่านข้อมูลต่อได้ทันทีโดยไม่ต้องไปนั่งประกอบร่างใหม่ให้เสียเวลา
มือใหม่มักสับสนระหว่าง JSON_VALUE กับ JSON_QUERY ให้จำง่ายๆ ว่าถ้าอยากได้ค่าแบบ "ข้อความ" ให้ใช้ VALUE แต่ถ้าอยากได้ "ก้อนข้อมูล" หรือ "รายการ" ให้ใช้ QUERY ถ้าเลือกใช้ผิดจะทำให้ข้อมูลที่ได้ออกมาเป็นค่าว่างหรือรูปแบบที่โปรแกรมอื่นอ่านไม่รู้เรื่องครับ
-- ดึงข้อมูลชุดย่อยที่เป็น JSON
SELECT JSON_QUERY(Details, '$.Specifications') AS Specs
FROM Products;
-- ดึงก้อนข้อมูลสเปกออกมาโดยยังคงรูปแบบ JSON ไว้
ฟังก์ชันนี้จะเข้าไปค้นหาข้อมูลในตำแหน่ง $.Specifications แล้วดึงข้อมูลทั้งหมดที่อยู่ภายใต้หัวข้อนี้ออกมา ผลลัพธ์ที่ได้จะเป็นก้อนข้อมูลเช่น {"Weight":"1kg", "Material":"Plastic"} ซึ่งเราสามารถนำไปใช้ต่อได้ทันที
แปลงข้อมูล JSON ให้กลับมาเป็นตารางด้วย OPENJSON()
ในทางกลับกัน ถ้าเรามีข้อมูล JSON ส่งมาจากแอปแล้วอยากเอามาเก็บลงตารางในฐานข้อมูล เราต้องใช้ OPENJSON() (คำสั่งแปลงข้อมูล JSON ให้กลายเป็นตาราง) เพื่อกระจายข้อมูลจากก้อนข้อความให้กลายเป็นแถวและคอลัมน์เหมือนข้อมูลปกติที่เราคุ้นเคย
มันเหมือนกับการแกะกล่องพัสดุแล้วเอาของข้างในมาวางเรียงบนโต๊ะเพื่อให้เราหยิบไปจัดเก็บในตู้ได้ง่ายขึ้น การใช้ OPENJSON ร่วมกับคำสั่ง WITH (คำสั่งระบุชื่อคอลัมน์สำหรับข้อมูลที่แปลง) จะทำให้เรากำหนดได้ชัดเจนว่าข้อมูลใน JSON แต่ละตัวจะไปอยู่ในคอลัมน์ไหนในตารางของเรา
นี่เป็นขั้นตอนสำคัญมากสำหรับโปรแกรมเมอร์เวลาทำระบบ Import (การนำเข้าข้อมูล) หรือรับข้อมูลจากระบบอื่นเข้ามา เพราะเราต้องตรวจสอบก่อนว่าข้อมูลที่แกะออกมานั้นถูกต้องตามกฎที่เราวางไว้หรือไม่ การใช้ WITH จะช่วยให้เรากำหนดชนิดข้อมูล (Data Type) ได้ด้วย ซึ่งช่วยป้องกันไม่ให้ข้อมูลผิดพลาดหลุดเข้าไปในฐานข้อมูลของเรา
-- แปลง JSON ให้เป็นตาราง
DECLARE @json NVARCHAR(MAX) = '{"Name":"Monitor","Price":5000}';
SELECT * FROM OPENJSON(@json)
WITH (Name NVARCHAR(50), Price INT);
-- แปลงข้อความ JSON ให้เป็นตารางที่มีคอลัมน์ Name และ Price
เราประกาศตัวแปร @json เพื่อเก็บข้อมูล JSON จากนั้นใช้ OPENJSON เพื่ออ่านข้อมูล และใช้ WITH เพื่อบอกว่าข้อมูลใน JSON ชื่อ Name ให้เก็บเป็นตัวอักษร และ Price ให้เก็บเป็นตัวเลข ผลลัพธ์ที่ได้จะเป็นตารางที่มี 1 แถว มีชื่อคอลัมน์ว่า Name และ Price เรียบร้อย
สรุป: เอาไปใช้จริงในงานโปรแกรมเมอร์อย่างไร
การจัดการ JSON ใน MS-SQL ไม่ใช่แค่เรื่องของการแปลงข้อมูลไปมา แต่มันคือการทำให้ระบบของเราสื่อสารกับโลกภายนอกได้ราบรื่นขึ้น ในชีวิตจริงคุณอาจจะได้รับ JSON จากเว็บเซอร์วิสมาเป็นก้อนใหญ่ๆ แล้วต้องใช้ OPENJSON เพื่อแยกข้อมูลไปเก็บในตารางหลักหลายๆ ตารางพร้อมกัน
หรือในทางกลับกัน เวลาคุณสร้าง REST API (มาตรฐานการส่งข้อมูลผ่านเว็บ) คุณอาจจะใช้ FOR JSON PATH เพื่อเตรียมข้อมูลให้หน้าเว็บแสดงผลได้เลยโดยไม่ต้องเขียนโค้ดฝั่งหลังบ้าน (Backend) ซับซ้อน การฝึกใช้ฟังก์ชันเหล่านี้จะช่วยให้คุณทำงานได้เหมือนมืออาชีพที่เข้าใจทั้งฐานข้อมูลและโครงสร้างข้อมูลที่ทันสมัย
คำแนะนำคือลองสร้างข้อมูลจำลองขึ้นมา แล้วหัดเขียนคำสั่งเหล่านี้ให้คล่อง เริ่มจากดึงข้อมูลออกก่อน แล้วค่อยหัดนำข้อมูลเข้า ถ้าคุณทำสองสิ่งนี้ได้จนชำนาญ คุณจะกลายเป็นโปรแกรมเมอร์ที่จัดการข้อมูลได้เก่งและเป็นที่ต้องการของทีมแน่นอน เพราะฐานข้อมูลคือหัวใจสำคัญของซอฟต์แวร์ทุกตัวครับ