Sebelum memulai coding, mumpung lagi di Jakarta dan dengan dengan Cafe sekitar Kemayoran kita bisa sambil menikmati Kopi dan Snack terlebih dahulu, selagi menunggu Mobil di service di bengkel Honda Harapan Indah kita coba untuk membuat 1 buah Script dimana fungsinya adalah mengkonversi sebuah Json String agar bisa diolah datanya. Tetapi kali ini bukan dari sisi aplikasi melainkan menggunakan PL/SQL yang tentunya pengolahan JSONString ini dilakukan didalam DATABASE.
JSON
JSON adalah turunan JavaScript yang digunakan dalam transfer dan penyimpanan data. Kekinian, bahasa ini sering dimanfaatkan dalam pembuatan aplikasi web.
Fungsi JSON kurang lebih sama dengan XML. Sebelum JSON diciptakan, format bahasa markup ini sering digunakan dengan JavaScript dalam AJAX (asynchronous JavaScript and XML) untuk penyimpanan dan perpindahan data.
Berkat gabungan keduanya, developer dapat membuat halaman website di mana informasinya dapat diperbarui tanpa harus memuat ulang halaman tersebut. Ini sudah menjadi hal yang umum, terutama dengan menjamurnya tren aplikasi web.
Nah, JSON memiliki fungsi yang sama. Bedanya, ia memiliki beberapa keunggulan yang membuatnya lebih sering digunakan daripada XML, termasuk:
- File yang lebih ringan
- Struktur kode yang lebih sederhana
- Kode yang mudah dipahami oleh manusia
Agar Anda paham dengan ketiga keunggulan tersebut, mari simak contoh yang ada di poin berikutnya.
Perbandingan JSON dan XML
Seberapa sederhanakah kode JSON jika dibandingkan dengan kode XML? Untuk mengetahuinya, Anda dapat memperhatikan kedua contoh di bawah ini. Contoh pertama adalah kode XML.
<users> <user> <username>Anton</username> <lokasi>Bandung</lokasi> </user> <user> <username>Budi</username> <lokasi>Semarang</lokasi> </user> <user> <username>Nana</username> <lokasi>Surabaya</lokasi> </user> <user> <username>Jamal</username> <lokasi>Tangerang</lokasi> </user> </users>
Nah, berikut ini adalah contoh kode JSON.
{"users": [ {"username" : "Anton", "lokasi" : "Bandung"}, {"username" : "Budi", "lokasi" : "Semarang"}, {"username" : "Nana", "lokasi" : "Surabaya"}, {"username" : "Jamal", "lokasi" : "Tangerang"} ] }
Dapat Anda lihat bahwa kode JSON lebih ringkas karena tidak memerlukan tag pembuka dan penutup. Dengan demikian, kodenya juga lebih mudah dipahami. Di samping itu, kelebihan ini juga memberikan dua manfaat lainnya, yaitu:
- Proses loading data yang lebih ringan karena ukuran file yang kecil.
- Penulisan kode yang lebih cepat dengan kode yang sederhana.
Database SQL Server
Sebelum saya ulas pengertian Microsoft SQL Server, saya akan coba pecah terlebih dahulu.
- SQL adalah singkatan atau kependekan dari Structured Query Language.
- SQL SERVER adalah sistem manajemen database relasional (RDBMS) yang dirancang untuk aplikasi dengan arsitektur client/server.
Istilah client, server, dan client/server dapat digunakan untuk merujuk kepada konsep yang sangat umum atau hal yang spesifik dari perangkat keras atau perangkat lunak. Pada level yang sangat umum. Jadi secara umum SQL Server adalah sebuah Software yang dibuat oleh perusahaan Microsoft yang digunakan untuk membuat database yang dapat diimplementasikan untuk Client Server.
- CLIENT adalah setiap komponen dari sebuah sistem yang meminta layanan atau sumber daya (resource) dari komponen sistem lainnya.
- SERVER adalah setiap komponen sistem yang menyediakan layanan atau sumber daya ke komponen sistem lainnya.
Apakah SQL Server bisa memanipulasi JSON ? Bisa. Pada SQL Server 2008r2, dapat dilakukan dengan cara membuat sebuah fungsi untuk memecah json string kedalam sebuah table. Sebetulnya syntax yang asli berasal dari situs web ini. https://en.dirceuresende.com/blog/lendo-strings-json-convertendo-tabelas-para-json-e-para-xml-no-sql-server/ , tetapi saya rubah ke bahasa yang lebih universal (Inggris).
Untuk penggunaannya sendiri sebagai berikut:
Buat Database pada SQL Server.
Untuk membuat database pada SQL Server bisa menggunakan script dibawah
USE master GO CREATE DATABASE DBTEST ON PRIMARY ( NAME = N'DBTEST', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\DBTEST.mdf', SIZE = 3072 KB, MAXSIZE = UNLIMITED, FILEGROWTH = 1024 KB ) LOG ON ( NAME = N'DBTEST_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\DBTEST_log.ldf', SIZE = 1024 KB, MAXSIZE = UNLIMITED, FILEGROWTH = 10 % ) GO ALTER DATABASE DBTEST SET ANSI_NULL_DEFAULT OFF, ANSI_NULLS OFF, ANSI_PADDING OFF, ANSI_WARNINGS OFF, ARITHABORT OFF, AUTO_CLOSE OFF, AUTO_CREATE_STATISTICS ON, AUTO_SHRINK OFF, AUTO_UPDATE_STATISTICS ON, AUTO_UPDATE_STATISTICS_ASYNC OFF, COMPATIBILITY_LEVEL = 100, CONCAT_NULL_YIELDS_NULL OFF, CURSOR_CLOSE_ON_COMMIT OFF, CURSOR_DEFAULT GLOBAL, DATE_CORRELATION_OPTIMIZATION OFF, DB_CHAINING OFF, HONOR_BROKER_PRIORITY OFF, MULTI_USER, NUMERIC_ROUNDABORT OFF, PAGE_VERIFY CHECKSUM, PARAMETERIZATION SIMPLE, QUOTED_IDENTIFIER OFF, READ_COMMITTED_SNAPSHOT OFF, RECOVERY FULL, RECURSIVE_TRIGGERS OFF, TRUSTWORTHY OFF WITH ROLLBACK IMMEDIATE GO ALTER DATABASE DBTEST COLLATE SQL_Latin1_General_CP1_CI_AS GO ALTER DATABASE DBTEST SET DISABLE_BROKER GO ALTER DATABASE DBTEST SET ALLOW_SNAPSHOT_ISOLATION OFF GO ALTER AUTHORIZATION ON DATABASE::DBTEST TO sa GO
Membuat Fungsi Convert JSONReader
CREATE FUNCTION dbo.fnJSONRead (@JSON NVARCHAR(MAX)) RETURNS @Retorno TABLE ( Id_Element INT NULL ,No_Sequence [INT] NULL ,Id_Object_Parent INT ,Id_Object INT ,Ds_Name NVARCHAR(2000) ,Ds_String NVARCHAR(MAX) NOT NULL ,Ds_Type VARCHAR(10) NOT NULL ) AS BEGIN DECLARE @FirstObject INT ,@OpenDelimiter INT ,@NextOpenDelimiter INT ,@NextCloseDelimiter INT ,@Type NVARCHAR(10) ,@NextCloseDelimiterChar CHAR(1) ,@Contents NVARCHAR(MAX) ,@Start INT ,@end INT ,@param INT ,@EndOfDs_Name INT ,@token NVARCHAR(200) ,@value NVARCHAR(MAX) ,@No_Sequence INT ,@Ds_Name NVARCHAR(200) ,@Id_Object_Parent INT ,@lenJSON INT ,@characters NCHAR(36) ,@result BIGINT ,@index SMALLINT ,@Escape INT DECLARE @Strings TABLE ( String_ID INT IDENTITY (1, 1) ,Ds_String NVARCHAR(MAX) ) SELECT @characters = '0123456789abcdefghijklmnopqrstuvwxyz' ,@No_Sequence = 0 ,@Id_Object_Parent = 0; WHILE (1 = 1) BEGIN SELECT @Start = PATINDEX('%[^a-zA-Z]["]%', @JSON COLLATE SQL_Latin1_General_CP850_BIN); IF (@Start = 0) BREAK IF (SUBSTRING(@JSON, @Start + 1, 1) = '"') BEGIN SET @Start = @Start + 1; SET @end = PATINDEX('%[^\]["]%', RIGHT(@JSON, LEN(@JSON + '|') - @Start) COLLATE SQL_Latin1_General_CP850_BIN); END IF (@end = 0) BREAK SELECT @token = SUBSTRING(@JSON, @Start + 1, @end - 1) SELECT @token = REPLACE(@token, FromString, ToString) FROM (SELECT '\"' AS FromString ,'"' AS ToString UNION ALL SELECT '\\' ,'\' UNION ALL SELECT '\/' ,'/' UNION ALL SELECT '\b' ,CHAR(08) UNION ALL SELECT '\f' ,CHAR(12) UNION ALL SELECT '\n' ,CHAR(10) UNION ALL SELECT '\r' ,CHAR(13) UNION ALL SELECT '\t' ,CHAR(09)) substitutions SELECT @result = 0 ,@Escape = 1 WHILE (@Escape > 0) BEGIN SELECT @index = 0 ,@Escape = PATINDEX('%\x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%', @token COLLATE SQL_Latin1_General_CP850_BIN) IF (@Escape > 0) BEGIN WHILE (@index < 4) BEGIN SELECT @result = @result + POWER(16, @index) * (CHARINDEX(SUBSTRING(@token, @Escape + 2 + 3 - @index, 1), @characters) - 1) ,@index = @index + 1; END SELECT @token = STUFF(@token, @Escape, 6, NCHAR(@result)) END END INSERT INTO @Strings (Ds_String) SELECT @token SELECT @JSON = STUFF(@JSON, @Start, @end + 1, '@string' + CONVERT(NVARCHAR(5), @@IDENTITY)) END WHILE (1 = 1) BEGIN SELECT @Id_Object_Parent = @Id_Object_Parent + 1 SELECT @FirstObject = PATINDEX('%[{[[]%', @JSON COLLATE SQL_Latin1_General_CP850_BIN) IF (@FirstObject = 0) BREAK IF (SUBSTRING(@JSON, @FirstObject, 1) = '{') SELECT @NextCloseDelimiterChar = '}' ,@Type = 'object' ELSE SELECT @NextCloseDelimiterChar = ']' ,@Type = 'array' SELECT @OpenDelimiter = @FirstObject WHILE (1 = 1) BEGIN SELECT @lenJSON = LEN(@JSON + '|') - 1 SELECT @NextCloseDelimiter = CHARINDEX(@NextCloseDelimiterChar, @JSON, @OpenDelimiter + 1) SELECT @NextOpenDelimiter = PATINDEX('%[{[[]%', RIGHT(@JSON, @lenJSON - @OpenDelimiter) COLLATE SQL_Latin1_General_CP850_BIN) IF (@NextOpenDelimiter = 0) BREAK SELECT @NextOpenDelimiter = @NextOpenDelimiter + @OpenDelimiter IF (@NextCloseDelimiter < @NextOpenDelimiter) BREAK IF SUBSTRING(@JSON, @NextOpenDelimiter, 1) = '{' SELECT @NextCloseDelimiterChar = '}' ,@Type = 'object' ELSE SELECT @NextCloseDelimiterChar = ']' ,@Type = 'array' SELECT @OpenDelimiter = @NextOpenDelimiter END SELECT @Contents = SUBSTRING(@JSON, @OpenDelimiter + 1, @NextCloseDelimiter - @OpenDelimiter - 1) SELECT @JSON = STUFF(@JSON, @OpenDelimiter, @NextCloseDelimiter - @OpenDelimiter + 1, '@' + @Type + CONVERT(NVARCHAR(5), @Id_Object_Parent)) WHILE ((PATINDEX('%[A-Za-z0-9@+.e]%', @Contents COLLATE SQL_Latin1_General_CP850_BIN)) <> 0) BEGIN IF (@Type = 'Object') BEGIN SELECT @No_Sequence = 0 ,@end = CHARINDEX(':', ' ' + @Contents) SELECT @Start = PATINDEX('%[^A-Za-z@][@]%', ' ' + @Contents COLLATE SQL_Latin1_General_CP850_BIN)--AAAAAAAA SELECT @token = SUBSTRING(' ' + @Contents, @Start + 1, @end - @Start - 1) ,@EndOfDs_Name = PATINDEX('%[0-9]%', @token COLLATE SQL_Latin1_General_CP850_BIN) ,@param = RIGHT(@token, LEN(@token) - @EndOfDs_Name + 1) SELECT @token = LEFT(@token, @EndOfDs_Name - 1) ,@Contents = RIGHT(' ' + @Contents, LEN(' ' + @Contents + '|') - @end - 1) SELECT @Ds_Name = Ds_String FROM @Strings WHERE String_ID = @param END ELSE SELECT @Ds_Name = NULL ,@No_Sequence = @No_Sequence + 1 SELECT @end = CHARINDEX(',', @Contents) IF (@end = 0) SELECT @end = PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%', @Contents + ' ' COLLATE SQL_Latin1_General_CP850_BIN) + 1 SELECT @Start = PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%', ' ' + @Contents COLLATE SQL_Latin1_General_CP850_BIN) SELECT @value = RTRIM(SUBSTRING(@Contents, @Start, @end - @Start)) ,@Contents = RIGHT(@Contents + ' ', LEN(@Contents + '|') - @end) IF (SUBSTRING(@value, 1, 7) = '@object') BEGIN INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Id_Object, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,SUBSTRING(@value, 8, 5) ,SUBSTRING(@value, 8, 5) ,'object' END ELSE BEGIN IF (SUBSTRING(@value, 1, 6) = '@array') INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Id_Object, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,SUBSTRING(@value, 7, 5) ,SUBSTRING(@value, 7, 5) ,'array' ELSE IF (SUBSTRING(@value, 1, 7) = '@string') INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,Ds_String ,'string' FROM @Strings WHERE String_ID = SUBSTRING(@value, 8, 5) ELSE IF (@value IN ('true', 'false')) INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,@value ,'boolean' ELSE IF (@value = 'null') INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,@value ,'null' ELSE IF (PATINDEX('%[^0-9]%', @value COLLATE SQL_Latin1_General_CP850_BIN) > 0) INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,@value ,'real' ELSE INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Ds_Type) SELECT @Ds_Name ,@No_Sequence ,@Id_Object_Parent ,@value ,'int' IF (@Contents = ' ') SELECT @No_Sequence = 0 END END END INSERT INTO @Retorno (Ds_Name, No_Sequence, Id_Object_Parent, Ds_String, Id_Object, Ds_Type) SELECT '-' ,1 ,NULL ,'' ,@Id_Object_Parent - 1 ,@Type DECLARE @Tabela_Final TABLE ( Id_Element INT IDENTITY (1, 1) NOT NULL ,No_Sequence [INT] NULL ,Id_Object_Parent INT ,Id_Object INT ,Ds_Name NVARCHAR(2000) ,Ds_String NVARCHAR(MAX) NOT NULL ,Ds_Type VARCHAR(10) NOT NULL ) INSERT INTO @Tabela_Final SELECT No_Sequence ,Id_Object_Parent ,Id_Object ,Ds_Name ,Ds_String ,Ds_Type FROM @Retorno ORDER BY ISNULL(Id_Object, Id_Object_Parent) DESC, Id_Object_Parent DESC, Id_Element DELETE FROM @Retorno INSERT INTO @Retorno SELECT Id_Element ,No_Sequence ,Id_Object_Parent ,Id_Object ,Ds_Name ,Ds_String ,Ds_Type FROM @Tabela_Final RETURN END GO
Cara pemakaian fungsi dengan perintah / contoh dibawah
DECLARE @jsonData NVARCHAR(MAX); SET @jsonData = '[{"item": "Kecap","harga": "5000"},{"item": "Merica","harga": "7500"},{"item": "Susu Beruang","harga": "15000"}]'; -- DEFAULT RESULT SELECT * FROM dbo.fnJSONRead(@jsonData) -- GROUPING SELECT tableValue.Id_Object_Parent ,tableValue.Ds_Name ,tableValue.Ds_String FROM dbo.fnJSONRead(@jsonData) tableKey INNER JOIN dbo.fnJSONRead(@jsonData) tableValue ON tableKey.Id_Object_Parent = tableValue.Id_Object_Parent WHERE tableKey.Ds_Name IS NOT NULL GROUP BY tableValue.Id_Object_Parent ,tableValue.Ds_Name ,tableValue.Ds_String -- FINAL RESULT: PIVOT TABLE SELECT item ,harga FROM (SELECT tableValue.Id_Object_Parent ,tableValue.Ds_Name ,tableValue.Ds_String FROM dbo.fnJSONRead(@jsonData) tableKey INNER JOIN dbo.fnJSONRead(@jsonData) tableValue ON tableKey.Id_Object_Parent = tableValue.Id_Object_Parent WHERE tableKey.Ds_Name IS NOT NULL GROUP BY tableValue.Id_Object_Parent ,tableValue.Ds_Name ,tableValue.Ds_String) AS T PIVOT ( MAX(T.Ds_String) FOR Ds_Name IN (item, harga) ) AS PT
Dengan perintah diatas didapat hasil sebagai berikut:
Untuk Database bisa di Download disini: Google Drive .