PANDUAN
QUERY MySQL
Tutorial dan referensi lengkap
SQL pada MySQL
INSERT SELECT
TRANSACTION
TRIGGERS
UPDATE
SQL
VIEWS EVENTS
CROSSTAB
DELETE DDL
Edisi : I (Pertama)
Dimensi : 15,7 cm x 23 cm
Penulis
Buku ini menggunakan dua database karena contoh query yang ada kurang
memadahi jika menggunakan satu database, sehingga untuk
mempraktekkan contoh query pada buku ini, Anda perlu memperhatikan
tabel yang digunakan apakah berada di database tutorial atau di database
toko_buku.
Selain file sql, juga disertakan file .php. File ini merupakan source code
script PHP yang digunakan pada pembahasan BAB 29 MySQL dan PHP.
Untuk menggunakannya, silakan letakkan file di dalam folder htdocs
kemudian akses file tersebut melalui browser. File php tersebut
menggunakan konfigurasi koneksi server: localhost, user: root, password:
'', jika konfigurasi server MySQL yang Anda gunakan berbeda, edit file .php
tersebut sebelum dijalankan
iv Source Code
Code Convention
Di dalam buku ini, Anda akan menemukan statemen SQL dimana beberapa
bagian dari SQL tersebut tidak wajib ditulis (opsional), atau mengharuskan
Anda untuk memilih salah satu opsi.
Pada contoh query diatas, karena klausa TO dan AS berada di dalam tanda
kurung siku, maka keduanya tidak wajib ditulis, sehingga Anda cukup
menuliskan:
Untuk bagian yang harus ada dan kita diharuskan memilih salah satu
klausa, tanda yang digunakan adalah kurung kurawal {}, misal:
vi Daftar Isi
4.4. Mengubah Database .................................................................................... 35
6.1. Numeric............................................................................................................. 63
6.3.2. TIME.......................................................................................................... 80
6.3.4. TIMESTAMP........................................................................................... 82
x Daftar Isi
10.4.2. Natural JOIN ....................................................................................... 158
11.2.3. UPDATE Baris Berdasarkan Nilai Pada Kolom Lain .......... 182
15.3.2. Subquery Dengan Hasil Lebih Dari Satu Row ...................... 276
22.4. Stored Procedure dengan Parameter IN, OUT, dan INOUT ..... 392
23.2. Stored Function Dengan Lebih Dari Satu Statemen Return .... 413
SQL dan database merupakan dua hal yang tidak dapat dipisahkan karena
kita perlu SQL untuk mengeksplorasi database. Pada BAB ini, kita akan
membahas secara singkat kedua istilah tersebut sehingga Anda memiliki
gambaran umum mengenai hal-hal yang akan dibahas dalam buku ini.
1.1. SQL
SQL (Structured Query Language) yang dibaca “sequel” adalah bahasa
standar yang digunakan untuk berkomunikasi dengan database
relasional, dengan kata lain, SQL merupakan bahasa yang digunakan user
untuk berinteraksi dengan database. SQL pertaama kali dibuat oleh IBM
sekitar tahun 1970. Bahasa tersebut awalnya dikembangkan untuk DB2
produk dari IBM (RDBMS yang saat ini masih eksis dan masih tersedian
di pasaran). Tahun 1979, Relation Software (yang kemudian berubah
nama menjadi ORACLE - saat ini menjadi salah satu leader teknologi
database relational) merelease produk pertamanya yaitu ORACLE.
Secara umum, terdapat tiga komponen utama bahasa SQL. Yang pertama
adalah DML atau Data Manipulation Language. Seperti arti “Data
Manipulation” yaitu manipulasi data, modul ini memungkinkan kita
untuk memanipulasi data, baik mengambil, menambah, mengubah, dan
menghapus data pada database, seperti penggunaan statemen SELECT,
UPDATE, INSERT, dan DELETE. Yang kedua adalah DDL atau Data
Definition Language. Seperti arti “Data Definition” yaitu mendefinisikan
data, modul ini memungkinkan kita membuat atau memodifikasi tabel
dan database, misal statemen CREATE, DROP, atau ALTER. Yang ketiga
adalah DCL, atau Data Control Language, yang berfungsi untuk
memastikan (meng kontrol) data yang dimasukkan telah sesuai dengan
tipe data yang disyaratkan.
Saat ini SQL tidak bisa lagi disebut sebagai bahasa deklaratif murni,
karena, sejak 1990, berbagai vendor database, termasuk MySQL
menambahkan ekstensi yang memungkinkan user untuk melakukan
pemrograman prosedural dengan SQL, seperti pada objek database
1.2. Database
Secara sederhana, database dapat diartikan sekumpulan catatan atau file
yang terorganisir untuk tujuan tertentu. Mungkin kita tidak menyadari
bahwa dalam keseharian, kita sering berinteraksi dengan database. Kita
mungkin mencatat nama dan alamat semua teman, relasi, atau pelanggan,
atau mungkin kita memiliki sekumpulan file dimana kita menyimpan
semua data rekening, arus kas, hutang, dan piutang, semua ini adalah
contoh bentuk database. Ketika kita bekerja dengan Microsoft Office, kita
kelompokkan file office kita berdasarkan topik tertentu, hal tersebut juga
merupakan salah satu bentuk lain dari database.
1.4. MySQL
MySQL dikenal sebagai "the world most popular open-source database"
yang artinya database open source paling populer di dunia. MySQL telah
digunakan oleh jutaan pengguna khususnya pada aplikasi berbasis web.
Pengguna database MySQL diantaranya adalah Facebook, Google,
Youtube, Alcatel Lucent, dan NASA. Meskipun terkenal digunakan pada
website, MySQL juga powerful ketiga digunakan secara offline (tidak
terhubung dengan internet).
MySQL yang dirilis pertama kali tahun 1995, pertama kali dikembangkan
oleh MySQL AB, perusahaan asal Swedia (inilah mengapa default
character set dan collation adalah latin_swedish_ci). Setelah rangkaian
Untuk dapat menjalankan latihan pada buku ini, kita perlu mendownload
dan menginstall MySQL. Kita dapat mendownload MySQL Community
Edition secara gratis di website www.mysql.com. Paket instalasinya sudah
mencakup command line client yang bernama mysql, yang dapat
digunakan untuk menjalankan berbagai statemen SQL melalui command
prompt. MySQL mendukung banyak platform, pada kesempatan ini , kita
hanya membahas instalasi pada Sistem Operasi Windows. Jika komputer
Anda sudah terinstall MySQL, Anda dapat melewati bagian ini.
Pada halaman berikutnya, jika tidak ingin login atau register, langsung saja
klik link "No thanks, just start my download".
STEP 1. Dobel klik file installer .msi untuk memulai proses instalasi.
Tunggu beberapa saat hingga muncul jendela MySQL Installer
Pada pilihan MySQL Server yang ingin diinstall, pilih sesuai dengan
arsitektur Windows yang sedang Anda gunakan, 32 atau 64 bit. Untuk
mengetahui arsitektur Windows yang sedang digunakan, klik kanan pada
Informasi jenis arsitektur ada pada pada bagian System Type. Pada contoh
kali ini, penulis menggunakan arsitektur Windows 64-bit.
Selanjutnya, klik bagian MySQL Server 5.7.17 – X64 kemudian klik tanda
panah kanan, untuk memasukkan ke dalam daftar produk yang akan
diinstall.
Pada bagian Config type, terdapat tiga pilhan mesin (komputer), yaitu:
Developer Machine, Server Machine, atau Dedicated MySQL Server
Machine. Pilihan ini akan mempengaruhi penggunaan porsi processor,
hardisk, dan memory (RAM). Jika Anda menggunakan pada komputer yang
digunakan untuk berbagai keperluan, pilih Development Machine. Jika
MySQL dijalankan di komputer bersama dengan server lain dan masih
tersedia cukup resource, pilih opsi Server Machine. Pilih Dedicated MySQL
Server Machine jika Server MySQL merupakan server utama dan sebagian
besar resource komputer dialokasikan untuk server tersebut.
STEP 4. Selanjutnya masuk ke bagian Accounts and Roles. Pada bagian ini,
kita harus mengisi MySQL Root Password dan Repeat Password. Password
ini akan digunakan untuk login dengan user root. Setelah selesai, klik Next
> untuk melanjutkan.
STEP 4. Selanjutnya masuk ke bagian Accounts and Roles. Pada bagian ini,
kita harus mengisi MySQL Root Password. Password ini akan digunakan
untuk login dengan user root. Setelah selesai, klik Next > untuk
melanjutkan.
Proses ini akan membuat file konfigurasi bernama my.ini yang ada di
dalam direktori C:\ProgramData\MySQL\MySQL Server 5.7. Selanjutnya
Anda dapat memodifikasi file tersebut menggunakan notepad atau text
editor lainnya. Setelah melakukan perubahan, Anda harus merestrart
MySQL server untuk melihat perubahan.
Pada buku ini, penulis menggunakan kombinasi antara command line dan
HeidiSQL. Sehingga, di beberapa bagian dari buku ini, Anda akan menemui
output dari command line dan di bagian lain, output dari HeidiSQL.
HeidiSQL ditulis oleh Ansgar Becker tahun 1999 dan sampai sekarang
masih terus dikembangkan. Meskipun ditulis oleh perorangan, software ini
tidak kalah dengan software buatan perusahaan besar. Terdapat dua versi
HeidiSQL, yaitu versi portable dan versi Installer. Pada BAB ini, kita akan
membahas cara menginstall HeidiSQL menggunakan versi Installer.
STEP 1. Dobel klik file installer yang telah didownload, dan tunggu hingga
muncul jendela Setup Wizard.
STEP 3. Pilih lokasi instalasi, atau biarkan apa adanya. Secara default,
software akan diinstall di C:\Program Files\HeidiSQL
STEP 6. Selanjutnya muncul resume opsi yang telah dipilih yang siap
dieksekusi. Klik Install untuk menginstall HeidiSQL dengan semua opsi
yang telah dipilih
Setelah proses instalasi selesai, klik Finish untuk menutup jendela Setup
Wizard, centang opsi Launch HeidiSQL untuk langsung mejalankan
HeidiSQL
4. Nomor 4 merupakan tab query yang merupakan tab dimana kita ingin
menuliskan query SQL. Tab ini dapat ditambah dengan meng-klik icon
plus yang ada di sebelah kanan nya. Tab ini tidak terpengaruh dengan
Pada database relasional seperti MySQL, data disimpan dalam bentuk tabel
yang terdiri dari baris (row) dan kolom (field). Sebuah database dapat
terdiri dari beberapa tabel, misal database toko_buku terdiri dari tabel
buku, pelanggan, dan penjualan.
Jika nama database telah ada, maka akan muncul pesan error, untuk
menghindarinya, kita dapat tambahkan klausa IF NOT EXISTS
Untuk melihat semua database yang ada, kita dapat menggunakan perintah
SHOW DATABASES
Pada contoh tersebut kita dapat menampilkan data tabel barang yang ada
pada database tutorial, meskipun saat ini kita sedang menggunakan
database penjualan. Pemilihan default database dengan keyword USE
dapat memudahkan kita untuk menjalankan berbagai query, karena kita
tidak perlu menuliskan nama database pada setiap query, misal:
Pada query diatas, MySQL akan menampilkan data tabel pelanggan pada
database toko_buku. Karena kita telah membuat tabel toko_buku sebagai
default database, maka secara implisit MySQL akan menambahkan nama
database yaitu toko_buku di depan nama tabel pelanggan.
Untuk menghindari error jika nama database tidak ditemukan, kita dapat
menambahkan klausa IF NOT EXISTS
Ketika menghapus database, maka semua isi yang ada pada database
tersebut juga akan ikut terhapus, seperti tabel, stored routines, dll,
disamping itu folder fisik database tersebut juga ikut terhapus.
Misal:
Catatan:
Pada contoh diatas, kita buat tabel dengan nama pelanggan yang berisi 4
kolom yaitu id_pelanggan, nama, alamat, dan email. Pada tiap-tiap kolom
tersebut, kita harus mendefinisikan tipe data yang ingin digunakan, seperti
INT dan VARCHAR, sedangkan untuk panjang data tidak wajib diisi. Lebih
jauh tentang tipe data dan panjang data dibahas pada BAB 6 Tipe Data
Terakhir, kita tambahan constrain pada kolom yaitu UNIQUE dan PRIMARY
KEY yang artinya dalam satu kolom tidak boleh ada nilai yang sama.
Constrain primary key menandakan bahwa kolom menjadi kunci utama
dari tabel. Lebih jauh tentang constrain dibahas pada BAB 7 Constrain.
Ketika membuat tabel, sebisa mungkin untuk menjadikan salah satu kolom
menjadi primary key, sehingga dapat dipastikan tidak ada baris yang nilai
nya sama, hal ini untuk menjaga integritas dan konsistensi data, karena
ketika melakukan proses update atau delete, baris yang sama tersebut
akan sama sama terpengaruh.
Sebagai tambahan, ketika membuat tabel, maka MySQL akan membuat file
dengan nama sama seperti nama tabel. File tersebut disimpan di dalam
folder yang bernama sama dengan nama database yang sedang digunakan.
Jika engine yang digunakan MyISAM, MySQL akan membuat 3 file yang
masing-masing ber ekstensi .frm, .MYD, dan .MYI, jika engine yang
digunakan InnoDB, maka MySQL akan membuat 2 file, masing-masing
berekstensi .frm dan .ibd misal pada contoh diatas, karena engine yang
digunakan adalah InnoDB, maka file yang terbentuk adalah
pelanggan.frm, pelanggan.ibd. File-file tersebut menyimpan baik data
maupun informasi terkait tabel.
Tidak boleh ada nama tabel yang sama dalam satu database.
Tidak boleh ada nama kolom yang sama dalam satu tabel, namun,
nama kolom yang sama dapat digunakan pada tabel yang berbeda.
Nama kolom dan tabel hanya boleh menggunakan huruf, angka, _ dan
$ dan maksimal 64 karakter. Selain itu, nama kolom dan tabel harus
diawali degan huruf atau angka.
Nama tabel dan kolom tidak boleh sama dengan keyword yang telah
digunakan oleh MySQL, seperti CASCADE, BEGIN, LEFT, dll
Lebih jauh, penentuan nama tabel dan kolom merupakan hal penting
karena dapat memudahkan kita dalam mengelola tabel, terutama jika
jumlah tabel banyak. Beberapa hal yang dapat dipertimbangkan ketika
memilih nama tabel atau kolom:
Beri nama tabel dan kolom dengan huruf kecil semua, meskipun SQL
bersifat case insensitive (tidak membedakan huruf besar dan kecil)
namun pemberian nama tabel dan kolom dengan huruf kecil akan
memudahkan kita ketika menulis query SQL karena dapat dibedakan
dengan mudah mana statemen SQL dan mana nama tabel atau kolom.
Dari tabel diatas terlihat bahwa storage engine default nya adalah InnoDB
Selain character set, kita juga dapat menentukan default collation pada
tabel, collation ini juga digunakan untuk mendefinisikan collation kolom
jika collation kolom tidak didefinisikan, untuk melihat semua collation
yang dapat digunakan, jalankan perintah berikut:
SHOW COLLATION
Hasil:
+--------------------------+----------+-----+---------+----------+---------+
| Collation | Charset | Id | Default | Compiled | Sortlen |
+--------------------------+----------+-----+---------+----------+---------+
| ... | ... | ... | ... | ... | ... |
| latin1_swedish_ci | latin1 | 8 | Yes | Yes | 1 |
| latin1_danish_ci | latin1 | 15 | | Yes | 1 |
| utf8_general_ci | utf8 | 33 | Yes | Yes | 1 |
| utf8_bin | utf8 | 83 | | Yes | 1 |
| utf8_unicode_ci | utf8 | 192 | | Yes | 8 |
| utf8_icelandic_ci | utf8 | 193 | | Yes | 8 |
| utf8_latvian_ci | utf8 | 194 | | Yes | 8 |
| ... | ... | ... | ... | ... | ... |
+--------------------------+----------+-----+---------+----------+---------+
Untuk collation yang membedakan huruf besar dan kecil, nama collation
tersebut biasanya berakhiran _cs yang artinya case sensitive, misal:
latin1_swedish_cs, sedangkan yang tidak membedakan huruf besar dan
kecil, biasanya berakhiran _ci yang artinya case insensitive, misal:
latin_swedish_ci.
Contoh 1: Character Set didefinisikan pada tabel namun tidak pada kolom
Pada contoh diatas, kolom_tes akan memiliki character set utf8 dan
collation utf8_unicode_ci. Hal ini dikarenakan kita tidak mendefinisikan
character set dan collation pada kolom, sehingga kolom akan
menggunakan collation dari tabel.
Pada contoh diatas, tabel kolom_coba memiliki character set latin1 dan
collation latin1_swedish_ci, karena collation tidak di definisikan, maka
otomatis mengambil default collation dari character set.
Pada contoh diatas, tabel kolom_coba memiliki character set latin1 dan
collation latin1_swedish_ci, karena character set kolom tidak di
definisikan, maka otomatis mengambil character set yang terkait dengan
collation kolom (biasanya kata depan dari collation).
Pada contoh diatas, kolom akan mencari default character set dan collation
pada tabel, karena pada tabel tidak didefinisikan, maka akan menggunakan
character set dan collation pada database, yang dalam hal ini adalah
latin1
Hal ini juga berlaku untuk tabel, karena kita tidak mendefinisikan
character set dan collation tabel, maka akan digunakan character set dan
collation dari database.
Catatan:
Misal kita copy tabel buku ke tabel buku_backup, query yang kita jalankan:
Pada contoh diatas terlihat bahwa index pada tabel buku juga ikut tercopy
termasuk kolom untuk foreign key, namun karena foreign key melibatkan
tabel lain, foreign key constrain tidak ikut terbentuk.
Statemen insert ini dibahas lebih jauh pada BAB 11 Manipulasi Data.
Misal, kita copy tabel buku ke tabel buku2, jalankan query berikut:
Jika tabel barang telah ada, maka akan muncul pesan error: SQL Error
(1050): Table 'barang' already exists
Collation tabel:
Selanjutnya mari kita ubah character set tabel pengarang menjadi utf8
Perintah diatas akan mengubah character set tabel menjadi utf8 dan
collation tabel menjadi utf8_general_ci, karena collation tidak
didefinisikan maka diambil collation default dari character set utf8, hal ini
juga berlaku untuk kolom:
Misal kita ubah character set tabel pengarang menjadi utf8 dan collation
utf8_unicode_ci:
Pada tipe data VARCHAR dan TEXT, perintah CONVERT TO CHARACTER SET
akan melakukan penyesuaian tipe data kolom untuk menyesuaikan
panjang data maksimal yang dapat diterima character set, misal pada
kolom dengan tipe data TEXT yang memiliki character set latin1, ketika
diubah menjadi utf8 tipe data akan berubah menjadi MEDIUMTEXT.
Perubahan tipe data tersebut dikarenakan pada character set latin1, setiap
karakter memiliki panjang data 1 byte, sedangkan pada utf8 panjang data
maksimal karakter adalah 3 byte, sehingga pada tipe data TEXT dengan
character set latin1 yang dapat menampung 65,535 karakter, ketika
berubah menjadi utf8, panjang data maksimal adalah 3 byte x 65,535 =
196,605 bytes, demikian juga dengan VARCHAR yang mungkin juga akan
diubah menjadi MEDIUMTEXT.
Perlu diperhatikan bahwa nilai auto_increment tidak boleh lebih kecil dari
data maksimal yang ada pada kolom, misal pada tabel pengarang, data
maksimal kolom id_pengarang adalah 13, sehingga kita hanya dapat
memberi nilai auto_increment 14 keatas, jika kita beri nilai kurang dari 14,
maka nilai auto_increment akan menjadi 14.
Penjelasan:
Pada contoh diatas, kolom alamat memiliki tipe data TEXT, posisinya
berada di bagian akhir dari daftar kolom
Pada contoh diatas, kolom email memiliki tipe data VARCHAR dengan
panjang data 50, serta tidak boleh berisi nilai NULL
Contoh3: misal kita tambahkan kolom website setelah kolom email, kolom
telp setelah kolom website, dan kolom kota pada bagian akhir tabel.
Jika kita ingin menambahkan banyak kolom di akhir tabel, kita dapat
menggunakan cara lain, yaitu hanya satu kali menulis klausa ADD, format
penulisannya adalah:
Contoh 4: Misal pada tabel pengarang, pada bagian akhir tabel kita
tambahkan kolom kota, kode_popinsi, kode_kabupaten. query yang kita
jalankan:
Contoh 1: pada tabel pengarang, kita ubah nama kolom nama menjadi
nama_pengarang. Jalankan Query berikut
Contoh 2: pada tabel pengarang, kita ubah nama kolom alamat menjadi
alamat_pengarang dan kita ubah tipe datanya menjadi VARCHAR(255),
selain itu kita pindah posisi kolom tersebut menjadi setelah kolom kota.
Catatan:
Jika kita hanya ingin mengubah atribut kolom (kolom definition) tanpa
mengubah nama kolom, maka kita dapat menggunakan klausa MODIFY.
Adapun format penulisannya adalah:
Contoh 3: pada tabel pengarang, kita ubah tipe data kolom email menjadi
VARCHAR(255) dan kita ubah nilai defaultnya menjadi anonym@gmail.com
Untuk mengubah hanya atribut default dari suatu kolom kita dapat
menggunakan klausa SET DEFAULT dan DROP DEFAULT, format
penulisannya adalah:
Contoh 4: Misal kita ubah nilai default kolom email pada tabel pengarang
menjadi noemail. Query yang kita jalankan:
Contoh 5: Misal, kita hapus nilai default pada kolom email, query yang kita
jalankan
Contoh 1: Misal kita ingin menghapus kolom kota pada tabel pengarang.
Query yang kita jalankan
Selain menghapus kolom satu per satu, kita dapat menghapus beberapa
kolom sekaligus dalam satu statemen.
Contoh 2: pada tabel pengarang, kita hapus kolom email dan website.
Query yang kita jalankan:
Catatan:
Catatan: sama seperti menghapus kolom, kita juga tidak dapat menghapus
tabel yang kolomnya sedang digunakan sebagai foreign key, baik sebagai
kolom foreign key maupun kolom referensi, jika tidak maka akan muncul
pesan error, misal: SQL Error (1217): Cannot delete or update a
parent row: a foreign key constraint fail
Pada MySQL, tipe data atau data type menunjukkan jenis data suatu kolom.
Ketika mendesain tabel pada database, mau tidak mau kita harus
menentukan tipe data apa yang akan kita gunakan pada kolom tersebut,
apakah karakter (string), angka (numerik), Boolean, Datetime, atau yang
lain, selain itu, kita juga harus mendefinisikan panjang datanya, misal
VARCHAR(50) yang artinya tipe data VARCHAR dengan panjang data 50
karakter.
Selain itu, memproses data yang kecil (data dengan panjang data kecil),
akan lebih cepat daripada data yang besar, terlebih jika data tersebut dapat
disimpan pada memory (RAM), misal seperti penentuan panjang data
untuk tipe data integer, pemrosesan tipe data INT(4) akan lebih cepat
daripada INT(11)
MySQL sendiri telah mensupport banyak tipe data, BAB ini akan membahas
lebih dalam tipe data yang didukung MySQL, seperti: Numeric, String,
Boolean, dan Datetime
6.1. Numeric
Tipe data numeric digunakan untuk menyimpan data berupa angka, tipe
data ini terbagi menjadi dua, yaitu yang hanya mendukung bilangan bulat
(exact value) dan dan yang mendukung bilangan pecahan (floating point).
Untuk bilangan bulat kita gunakan tipe data TINYINT, SMALLINT,
Storage
Tipe Data Value
(byte)
Masing masing tipe data Integer dapat kita definisikan panjang data nya,
namun panjang data ini tidak berpengaruh apa apa, baik pada besarnya
ruang penyimpanan maupun banyaknya data yang ditampung. Misal
meskipun kita mendefinisikan integer dengan TINYINT(2), kita tetap
dapat memasukkan nilai 126, disamping itu, ruang penyimpanan yang
digunakan tetap 1 byte (4 bits), sehingga, untuk praktisnya, kita tidak perlu
menentukan panjang data, biarkan MySQL yang mendefinisikannya.
Contoh penggunaan tipe data numeric adalah ketika kita membuat tabel
nilai ujian dengan rentang nilai 0 s.d 100, karena nilai dibawah 127, maka
maka tipe data yang pas adalah TINYINT. Contoh lain adalah ketika kita
ingin menyimpan data pembayaran nasabah bank, karena nilainya besar
dan nilainya selalu positif, maka kita gunakan tipe data INT UNSIGNED,
namun, ketika suatu saat nilai data yang disimpan melebih batas, misal Rp.
5 milyar, maka data tersebut akan terpotong menjadi 4.294.967.295 (batas
maksimal tipe data INT UNSIGNED), sehingga perlu diubah menjadi BIGINT.
6.1.2. Desimal
Bentuk kedua setelah fixed point adalah decimal. Pada jenis ini, terdapat
tiga tipe data yang dapat digunakan, DECIMAL (fixed point), FLOAT dan
DOUBLE (floating point).
DECIMAL(M, D)
Tipe data DECIMAL juga dapat diberi atribut UNSIGNED, namun tidak seperti
pada INTEGER, unsigned pada DECIMAL hanya membatasi nilai negatif,
tidak memperbesar jangkauan data yang dapat ditampung.
Sama seperti DECIMAL, FLOAT dan DOUBLE juga dapat menerima atribut
UNSIGNED yang artinya hanya dapat menerima nilai positif, selain itu,
FLOAT dan DOUBLE juga dapat menerima argumen M dan D. Nilai dari M
antara 1 s.d 255, sedangkan untuk D antara 0 s.d 30, dan tidak boleh lebih
besar dari M. M dan D bersifat opsional, jika keduanya tidak didefinisikan,
maka desimal akan disimpan dengan presisi penuh (full precision) yang
dapat dilakukan oleh hardware komputer.
Hal ini terjadi karena pada tipe data decimal, nilai yang disimpan benar
benar 10.15, sedangkan pada float, nilai yang disimpan bukan 10.15, mari
kita tes:
Dari berbagai contoh diatas, dapat diketahui bahwa tipe data floating-point
memiliki nilai yang tidak pasti, sehingga agak merepotkan, untuk itu,
utamakan menggunakan tipe data decimal.
6.1.3. BIT
Tipe data BIT digunakan untuk menyimpan data binary digit (BIT), binary
merupakan kombinasi angka yang terdiri dari 0 dan 1. BIT memiliki
kapasitas 1 hingga 64 digit, jika panjang digit tidak didefinisikan, maka
secara default panjangnya adalah 1 digit. BIT(1) hanya dapat menyimpan
sebuah nilai 0 atau 1, BIT(2) dapat menyimpan 2 digit kombinasi 0 dan 1,
Pada contoh diatas, BOOLEAN dapat diganti BOOL. Contoh data untuk tabel
user:
Karena panjang data maksimal TINYINT adalah 127, maka kolom status
tersebut dapat kita isi nilai 0 s.d 127, tidak hanya 1 atau 0, meski demikian
tipe data tersebut hanya membutuhkan ruang 1 byte
Selain itu, terdapat juga atribut ZEROFILL. Seperti terjemahannya, yaitu isi
dengan nol, dengan atribut ini, maka jika data yang akan dimasukkan
memiliki panjang data lebih kecil dari yang telah ditetapkan, maka di
depannya akan ditambahkan angka 0 sebanyak sisa digit yang kurang.
Misal:
Atribut AUTO INCREMENT dapat diterapkan baik pada tipe data integer
maupun floating point. Gunakan atribut ini jika kita ingin memiliki kolom
dengan angka unik yang berurutan (series) seperti (1, 2, 3, dst…). Agar
MySQL memberikan angka series maka ketika memasukkan data, kolom
tersebut tidak perlu diisi, atau diisi dengan nilai NULL, seperti pada contoh
diatas ( INSERT pada tabel tes_numeric_attribute). Urutan digit tersebut
akan terus berlanjut meski ada baris yang dihapus, contoh
Pada contoh diatas, terlihat bahwa setelah data dihapus, nilai kolom
int_ai melanjutkan nilai series digit berikutnya yaitu 2. Nilai series digit
akan direset jika kita kosongkan tabel menggunakan statemen TRUNCATE
TABLE.
Dalam satu tabel, hanya boleh ada satu kolom dengan atribut AUTO
INCREMENT dan kolom tersebut harus memiliki constraint NOT NULL, jika
kita tidak mendefinisikan constraint tersebut, maka MySQL otomatis akan
menambahkannya, selain itu, kolom tersebut juga harus menjadi index,
umumnya index yang digunakan adalah PRIMARY KEY atau UNIQUE KEY.
Karena urutan digit selalu positif (dimulai dari 1), maka agar jangkauan
data lebih lebar, kolom tersebut dapat kita beri atribut UNSIGNED
6.2. String
String yang kita kenal umumnya berupa teks, namun demikian, string juga
dapat berupa data biner (binary) seperti file gambar, suara, dll. MySQL
menyediakan berbagai tipe data untuk menyimpan string, tabel 15.1 berisi
daftar tipe data string yang didukung oleh MySQL
Keterangan:
W atau width merupakan besarnya byte tiap satu karakter. Hal ini
tergantung dari jenis karakter set. Untuk karakter ASCII (yang sering
kita gunakan - bahasa Indonesia atau Inggris) nilai w adalah 1 byte,
sedangkan untuk karakter khusus seperti arab, nilai w bisa 2-3 byte.
L atau length merupakan panjang data aktual dalam byte, misal untuk
CHAR, L diperoleh dari M x W, sedangkan untuk Binary L = M.
Mungkin Anda bertanya tanya kalau begitu bukankah lebih efisien untuk
selalu menggunakan tipe data VARCHAR? Jawabnya tidak selalu, tergantung
kondisi yang ada. Berikut ini beberapa hal yang dapat dipertimbangkan
ketika menggunakan CHAR atau VARCHAR
Untuk data yang panjang datanya berubah ubah seperti data nama,
maka lebih efisien menggunakan VARCHAR, misal VARCHAR(50),
sehingga nama yang terdiri dari 7 karakter akan membutuhkan space
8-9 byte, namun jika kita gunakan CHAR(50) nama dengan jumlah
karakter berapapun akan membutuhkan tempat penyimpanan 50
byte.
Untuk data yang panjangnya tetap gunakan tipe data CHAR, misal pada
NIK pegawai yang panjangnya selalu 9 digit, kita gunakan tipe data
CHAR(9), jika menggunakan tipe data VARCHAR(9) maka akan
memerlukan tambahan ruang 1 atau 2 byte.
BLOB merupakan kependekan dari Binary Large Object. Tipe data BLOB
dapat digunakan untuk menyimpan data apa saja. Varian BLOB, yaitu
TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB memiliki fungsi yang sama hanya
berbada pada kapasitas penyimpanannya saja.
Tipe data TEXT umumnya text digunakan untuk menyimpan string yang
panjang, misal untuk artikel pada suatu website, deskripsi produk, dll,
sedangkan BLOB digunakan untuk menyimpan binary string dari file
seperti binary string file gambar. Contoh pada PHP:
1. $id = 1;
2. $binary = file_get_contents(gambar.jpg);
3. $query = 'INSERT INTO gallery (id, file) VALUES ($id, $binary)';
Tipe data ENUM umumnya digunakan untuk menyimpan data opsi yang
bernilai tunggal. Misal untuk opsi jenis kelamin ENUM('L', 'P') atau opsi
yang hanya memberikan nilai Yes atau No ENUM('Y', 'N'). Contoh lain:
opsi ukuran produk ENUM('S','M','L','XL'), opsi warna
ENUM('Hitam','Merah','Biru'), atau survey dengan jawaban yang telah
ditentukan.
Tipe data SET umumnya digunakan untuk menyimpan data opsi bernilai
jamak. Karakteristik opsi yang bernilai jamak adalah opsi satu dengan yang
lain dapat saling menggantikan, tidak berdiri sendiri, misal data pilihan
universitas pada pendaftaran beasiswa, gunakan tipe data ENUM('UI',
'UGM','UNS'), sehingga pilihan dapat berupa UGM saja, UI,UGM,
UGM,UNS, dst..
Secara internal, daftar pada ENUM dan SET disimpan berdasarkan urutan
index, dimana nilai awal index adalah 1, sehingga jika kita melakukan
pengurutan data, maka akan diurutkan berdasarkan index, bukan string.
Misal kita memiliki tabel tes_enum sebagai berikut:
Jika data kita urutkan berdasarkan abjad (col_enum), maka hasil yang kita
peroleh adalah:
Selain itu, kita juga dapat memfilter data berdasarkan nilainya, misal:
6.3.1. DATE
Pada MySQL, tanggal (date) harus ditulis menggunakan format tertentu,
format tanggal yang digunakan adalah 4 digit tahun, 2 digit bulan, dan 2
digit tanggal, dengan separator dash (-), misal 2017-03-10. Format ini
merupakan format baku sesuai spesifikasi standar SQL dalam ISO 8601.
Jika kita memasukkan data dengan format yang tidak baku, maka kita perlu
mengubahnya ke bentuk baku menggunakan fungsi STR_TO_DATE, misal:
6.3.2. TIME
Pada MySQL, waktu (time) juga harus ditulis menggunakan format
tertentu. Standard format waktu yang digunakan adalah jam:menit:detik
yang masing masing terdiri dari dua digit, misal 10:08:17. Sebagai
tambahan, kita dapat menambahkan microsecond hingga 6 digit, misal
15:08:10.436574.
Ketika memasukkan data tanggal dan waktu pada kolom dengan tipe data
tanggal atau waktu saja, maka otomatis data tersebut disesuaikan dengan
tipe data kolom, misal:
6.3.3. YEAR
Tipe data YEAR digunakan untuk menyimpan data tahun. Jumlah digit
tahun bisa 2 atau 4, defaultnya 4 digit tahun. Digit tersebut didefinisikan
ketika mendefinisikan kolom, yaitu YEAR(4) untuk 4 digit tahun dan
YEAR(2) untuk 2 digit tahun. YEAR dengan panjang 4 digit dapat
menampung tahun mulai dari tahun 1901 2155
Dua digit tahun akan mengambil tahun dari belakang sebanyak dua digit,
misal 17 untuk tahun 2017. Rentang tahun yang dapat disimpan adalah
1970 s.d 2069. Jika diluar itu, maka data menjadi ambigu misal 70 dapat
berarti 1970 dan 2070, karena kekurangan ini, maka mulai MySQL versi
5.6.6, penggunaan dua digit tahun sudah tidak disarankan lagi
(deprecated).
6.3.4. TIMESTAMP
TIMESTAMP merupakan gabungan dari DATE dan TIME dalam format UNIX
timestamp, disebut timestamp karena tipe data ini merujuk ke waktu
tertentu, lebih tepatnya detik tertentu dari waktu tertentu. Acuan waktu
untuk TIMESTAMP adalah 1970-01-01 00:00:00, sehingga timestamp 1
berarti 1970-01-01 00:00:01
Query tersebut dijalankan pukul 10:34:56, sehingga waktu UTC atau GMT
+ 0 adalah pukul 03:34:56 atau selisih 7 jam, hal tersebut karena kita
menggunakan zona waktu GMT + 7. Untuk mengetahui time zone yang
sedang digunakan, buka variabel @@session.time_zone
Selanjutnya, jika data tersebut dipanggil maka akan diubah menjadi GMT
sesuai dengan zona waktu user yang memanggilnya (hal ini tidak terjadi
pada tipe data lain seperti DATETIME).
Misal:
Misal:
Contoh lainnya adalah Website multi user dengan user dari berbagai
negara, sehingga event yang terjadi seperti INSERT, UPDATE atau
DELETE data dapat diketahui sesuai zona waktu masing masing.
Selain itu, untuk data waktu yang nilainya bervariasi, maka kita bisa
menggunakan DATETIME misal waktu yang hanya terdiri dari tahun
dan bulan, seperti 2017-03-00 00:00:00
Bentuk constrain ini sangat banyak tidak terbatas pada bentuk tertentu,
jika memenuhi kriteria diatas, maka bisa disebut constrain meskipun
bentuknya stored program seperti trigger. Untuk membatasi pembahasan,
pada bab ini, kita hanya akan membahas beberapa constrain eksplisit yang
didukung oleh MySQL, yaitu NOT NULL, PRIMARY KEY, UNIQUE, FOREIGN
KEY, ENUM, SET, dan CHECK.
Pada contoh diatas, terlihat bahwa kita tidak mendefinisikan nilai pada
kolom tgl_trx, hasilnya, kolom tersebut akan berisi tanggal dan waktu
ketika data dimasukkan. Perhatikan bahwa nilai pada kolom total_trx
bernilai NULL, hal ini dikarenakan jika kita tidak mendefinisikan nilai
default pada kolom yang dapat menerima NULL, maka MySQL akan
menambahkan klausa DEFAULT NULL pada kolom tersebut. Namun
demikian klausa DEFAULT tidak ditambahkan pada kolom dengan kriteria
NOT NULL. Mari kita lihat definisi dari tabel pelanggan
88 BAB 7 Constrain
mysql> INSERT INTO penjualan (id_trx) VAlUES (3);
ERROR 1364 (HY000): Field 'id_pelanggan' doesn't have a default
value
Pada contoh diatas, terlihat bahwa jika kita memberi nilai NULL maka akan
muncul pesan error Column ERROR 1048 (23000): 'id_pelanggan' cannot
be null namun error ini tidak terjadi dika kita memberi string kosong ''
pada kolom id_pelanggan
Pada contoh diatas, pada kolom id_trx kita definisikan atribut PRIMARY
KEY setelah atribut NOT NULL, atribut NOT NULL juga dapat ditulis setelah
atribut PRIMARY KEY.
Perlu diperhatikan bahwa karena dalam satu tabel hanya boleh memiliki
satu primary key, maka untuk pendefinisian primary key pada level kolom,
hanya bisa didefinisikan pada satu kolom, pendefinisian pada kolom yang
lain akan dianggap membuat primary key baru.
90 BAB 7 Constrain
Ketika mendefinisikan primary key, MySQL akan langsung membuat
index yang terdiri dari kolom yang dijadikan sebagai primary key.
Tabel hanya boleh memiliki satu primary key, hal ini merupakan
standar baku model database relasional yang juga diterapkan oleh
MySQL. Satu primary key tersebut dapat terdiri dari lebih dari satu
kolom, untuk membuatnya kita harus mendefinisikan primary key
pada level tabel bukan kolom.
Misal pada contoh sebelumnya kita buat PRIMARY KEY yang terdiri dari
kolom id_trx dan id_pelanggan
Pada data diatas, kombinasi nilai pada kolom id_trx dan id_pelanggan
tidak ada yang sama.
Pada contoh diatas terlihat bahwa primary key yang kita buat otomatis
diberi nama PRIMARY
Baik primary key maupun unique key, keduanya akan dijadikan index,
namun nama index untuk UNIQUE KEY dapat kita tentukan sendiri,
sedangkan pada PRIMARY KEY, namanya selalu PRIMARY.
92 BAB 7 Constrain
Jika pada primary key satu tabel hanya bisa memiliki satu primary key,
maka untuk unique key, satu tabel bisa memiliki lebih dari satu unique
key.
Kolom yang memiliki atribut unique key dapat bernilai NULL, sehingga
perlu diperhatikan pemberian atribut NULL pada kolom yang akan
dijadikan sebagai unique key.
Sama seperti primary key, kita dapat mendefinisikan unique key pada level
kolom dan tabel. Pada level kolom, kita dapat mendefinisikan unique key
pada beberapa kolom, yang artinya kita akan membuat lebih dari satu
unique key. Misal pada tabel penjualan kita buat unique key pada kolom
id_trx dan id_pelanggan
Pada contoh diatas, MySQL akan otomatis membuat dua buah index
dengan nama sesuai dengan nama kolom, yaitu index bernama id_trx
yang terdiri dari kolom id_trx, dan id_pelanggan yang terdiri dari kolom
id_pelanggan
Pada level tabel, kita dapat mendefinisikan sendiri nama index, selain itu,
kita juga dapat membuat index yang terdiri dari gabungan dari beberapa
kolom. Misal:
Jika kita tidak mendefinisikan nama index, maka MySQL akan memberi
nama index tersebut sesuai dengan nama kolomnya. Misal
Pada contoh diatas, MySQL akan membuat dua index, yaitu index dengan
nama id_trx yang terdiri dari kolom id_trx dan id_pelanggan dan
id_trx_2 yang terdiri dari hanya satu kolom, yaitu id_trx.
Pembuatan foreign key dapat dilakukan pada saat pembuatan tabel. Misal
kita akan membuat tabel pelanggan dan penjualan, dimana nilai pada
kolom id_pelanggan yang ada pada tabel penjualan harus ada pada
kolom id_pelanggan yang ada pada tabel pelanggan
Tabel pelanggan:
94 BAB 7 Constrain
6. )
Tabel penjualan:
Pada query yang digunakan untuk membuat tabel penjualan, kita gunakan
klausa FOREIGN KEY. Klausa ini terdiri dari tiga bagian yaitu:
Bagian pertama adalah kolom yang akan dijadikan sebagai foreign key.
Pada contoh diatas adalah kolom id_pelanggan yang ada pada tabel
penjualan. (FOREIGN KEY (`id_pelanggan`) )
Yang kedua adalah kolom pada tabel lain yang akan digunakan sebagai
referensi, dalam contoh ini adalah kolom id_pelanggan yang ada pada
tabel pelanggan (REFERENCES pelanggan (`id_pelanggan`) )
Yang ketiga adalah referensi aksi, yang artinya jika terjadi perubahan
data pada kolom referensi (kolom id_pelanggan pada tabel
pelanggan) yaitu berupa statemen UPDATE atau DELETE, maka kita
tentukan aksi apa yang akan diterapkan pada kolom foreign key.
Bagian ketiga ini tidak ada pada contoh. Kita akan membahasnya pada
bagian 7.6 Referensi Aksi.
Beberapa hal yang perlu diperhatikan ketika membuat foreign key, yaitu:
Kedua kolom baik kolom foreign key maupun kolom referensi harus
memiliki tipe data yang sama persis, termasuk penggunaan atribut
UNSIGNED pada tipe data INT. INT(11) tidak sama dengan INT(11)
UNSIGNED.
Storage Engine yang digunakan oleh kedua tabel harus InnoDB, engine
yang lain, seperti MyISAM tidak mendukung foreign key constrain.
Untuk mengecek storage engine yang ada beserta fitur yang dimiliki,
jalankan perintah SHOW ENGINES
96 BAB 7 Constrain
| InnoDB | DEFAULT | Supports transactions | YES |
| MRG_MYISAM | YES | Collection of ... | NO |
| MEMORY | YES | Hash based, stored... | NO |
| BLACKHOLE | YES | /dev/null storage... | NO |
| MyISAM | YES | MyISAM storage ... | NO |
| CSV | YES | CSV storage engine... | NO |
| ARCHIVE | YES | Archive storage ... | NO |
| PERFORMANCE_SCHEMA | YES | Performance Schema ...| NO |
| FEDERATED | NO | Federated MySQL ... | NULL |
+--------------------+---------+-----------------------+--------------+
Pada tabel diatas, agar tabel yang ditampilkan lebih simpel dan to the
point, beberapa kolom dihilangkan.
Pada tabel diatas, terlihat bahwa storage engine default adalah InnoDB,
kita dapat mengubah default storage engine dengan mengubah
variabel global storage engine:
Setelah foreign key berhasil dibuat, maka MySQL akan menjamin bahwa
nilai (selain NULL) yang dimasukkan ke dalam kolom foreign key akan ada
pada kolom referensi pada tabel referensi. Pada contoh diatas, nilai pada
kolom id_pelanggan yang ada pada tabel penjualan akan selalu ada pada
kolom id_pelanggan yang ada pada tabel pelanggan, sehingga, jika hal
tersebut tidak terpenuhi baik ketika user memasukkan atau mengubah
data (statemen INSERT atau UPDATE) maka akan muncul pesan error dan
proses manipulasi data tidak dilanjutkan. Sebagai contoh misal tabel
pelanggan berisi data sebagai berikut:
+--------------+----------+---------------------+
| id_pelanggan | nama | email |
+--------------+----------+---------------------+
| 1 | Anton | anton@gmail.com |
| 2 | Braskie | braskie@yahoo.com |
| 3 | Charlie | charlie@gmail.com |
| 4 | Deni | deni@gmail.com |
+--------------+----------+---------------------+
Maka jika kita ubah data id_pelanggan pada tabel pelanggan yang
memiliki nilai 1, akan muncul pesan error:
98 BAB 7 Constrain
mysql> UPDATE pelanggan SET id_pelanggan = 5 WHERE
id_pelanggan = 1;
ERROR 1451 (23000): Cannot delete or update a parent row: a
foreign key constraint fails (`toko_buku`.`penjualan`,
CONSTRAINT `penjualan_ibfk_1` FOREIGN KEY (`id_pelanggan`)
REFERENCES `pelanggan` (`id_pelanggan`))
3. SET NULL. Maksudnya, jika data pada kolom referensi diubah, maka
data yang ada pada kolom foreign key akan berubah menjadi NULL.
Misal jika kita ubah data id_pelanggan pada tabel pelanggan dari 1
menjadi 5, maka data pada tabel penjualan yang memiliki id 1 akan
berubah menjadi NULL.
Penting diperhatikan bahwa karena data pada kolom foreign key akan
diubah menjadi NULL, maka kolom tersebut harus bisa menerima nilai
NULL, misal pada pembuatan tabel, agar dapat menerima nilai NULL,
kita tidak boleh mendefinisikan NOT NULL pada kolom tersebut.
Pada contoh diatas, jika data id_pelanggan pada tabel pelanggan diubah
maka data id_pelanggan yang sama yang ada pada tabel penjualan juga
akan berubah, sedangkan jika data id_pelanggan pada tabel pelanggan
dihapus, maka jika data tersebut ada pada tabel penjualan maka proses
akan dihentikan (restrict).
Pada contoh diatas, sebelum data dimasukkan atau ada perubahan data
pada kolom jenis kelamin, akan dilakukan pengecekan apakah data
bernilai L atau P, jika tidak keduanya, maka akan muncul pesan error.
Dengan memberi nama constraint dengan nama yang jelas, maka error
tersebut akan dapat segera diatasi. Misal pada tabel pelanggan terdapat
constraint unique sebagai berikut:
Ketika kita isikan nilai 1 lebih dari satu kali pada kolom id_trx, maka akan
muncul pesan error:
Dari pesan tersebut dapat diketahui bahwa terdapat duplikasi nilai pada
kolom id_trx, namun demikian, jika constraint terdiri dari kombinasi dua
kolom maka akan pesan error akan lebih susah dipahami. Misal:
MySQL menyebutkan duplikasi data pada key id_trx, dari pesan tersebut
terlihat bahwa nama constraint diambil dari nama kolom pertama, yaitu
id_trx, agar lebih mudah diidentifikasi, kita perlu mengubah nama
constraint tersebut. Untuk mendefinisikan nama constrain, sebelum kita
menuliskan jenis constraint, tambahkan klausa CONSTRAINT diikuti nama
constraint. Misal
Pada contoh diatas, kita beri nama constrain sesuai dengan nama kolom
yang terlibat yaitu id_trx dan id_pelanggan. Ketika kita masukkan data
yang sama dua kali ke kolom id_trx dan id_pelanggan, maka kita akan
mendapati pesan error:
Dari pesan diatas dapat langsung kita ketahui bahwa terdapat duplikasi
data pada kombinasi kedua kolom tersebut.
Selain constraint UNIQUE, kita juga dapat memberi nama constraint pada
FOREIGN KEY constraint. Caranya juga sama yaitu dengan menambahkan
klausa CONSTRAINT sebelum klausa FOREIGN KEY, misal:
1. SELECT *
2. FROM information_schema.key_usage_column
3. WHERE constraint_schema = 'nama_database';
1. SELECT *
2. FROM information_schema.referential_constraints
3. WHERE constraint_schema = 'nama_database';
Terdapat cara alternatif untuk mengetahui constraint yang ada pada tabel
yaitu melihat statement yang digunakan untuk membuat tabel, caranya,
gunakan statement SHOW CREATE TABLE, misal:
Pada BAB ini, kita akan mulai membahas tentang SQL dari syntax yang
paling dasar yaitu statemen SELECT, pada bab-bab berikutnya kita bahas
berbagai syntax lainnya yang lebih kompleks. Statemen SELECT digunakan
terutama untuk mengambil data dari database, statemen ini merupakan
bagian paling penting dari SQL, karena request/query yang paling sering
kita lakukan adalah mengambil data untuk ditampilkan ke user, baik
sifatnya kompleks seperti laporan atau sekedar data sederhana.
Pada SQL dan bahasa pemrograman secara umum, kata tertentu disebut
keyword. Keyword ini memiliki arti khusus dan pada kondisi tertentu harus
ada. Pada contoh diatas, kata SELECT dan FROM adalah keyword. Keyword
SELECT menandakan bahwa statemen SELECT dimulai. Keyword ini diikuti
nama kolom dari tabel yang ingin diambil datanya, sedangkan keyword
FROM digunakan untuk menentukan tabel yang akan diambil datanya. Pada
Contoh diatas digunakan untuk mengambil data hanya dari satu kolom,
untuk mengambil lebih dari satu kolom, kita gunakan tanda koma sebagai
pemisah kolom, sedangkan untuk mengambil semua kolom, kita gunakan
tanda bintang/asterik (*).
Pada contoh diatas, syntax akan menghasilkan tabel sama persis seperti
yang ada pada database. Sebagai catatan, pada tabel yang memiliki banyak
kolom, menyeleksi semua field hanya untuk digunakan beberapa saja tidak
efektif, sehingga sebisa mungkin mendefinisikan nama field, hal ini
merupakan salah satu bentuk optimasi query.
Pada contoh diatas kita tampilkan 2 kolom yaitu kolom id_buku dan
pengarang. Urutan kolom yang ditampilkan sesuai dengan urutan kolom
yang ditulis pada perintah SQL.
Catatan:
SELECT nama_kolom
FROM nama_tabel
[WHERE kondisi]
[GROUP BY nama_kolom]
[ORDER BY nama_kolom]
[HAVING kriteria]
[LIMIT jumlah]
Keyword selain SELECT dan FROM bersifat opsional, jika disertakan, maka
harus sesuai dengan urutan diatas.
Nama kolom, tabel, dan database bersifat case sensitive, yang artinya
tidak membedakan huruf besar, misal SELECT judul FROM buku1
dapat ditulis select JUDUL from BUKU1
Pada contoh diatas, SELECT, FROM, dan WHERE merupakan keyword utama,
sehingga kita tulis pada baris baru.
Pada contoh diatas, statemen pertama adalah INSERT INTO buku (judul)
VALUES ('MySQL') sedangkan statemen kedua adalah SELECT judul
FROM buku, keduanya dipisah dengan titik koma
1. SELECT DISTINCT(id_penerbit)
2. FROM buku1
Hasil:
+-------------+
| id_penerbit |
+-------------+
| 1 |
| 4 |
+-------------+
Perlu diperhatikan bahwa DISTINCT ini hanya dapat digunakan pada satu
kolom, misal jika kita jalankan query berikut:
1. SELECT judul
2. FROM buku1
3. WHERE id_penerbit = 4
Pada contoh diatas, kita hanya menampilkan judul buku yang memiliki
id_penerbit 4.
8.5. GROUP BY
Klausa GROUP BY digunakan untuk mengelompokkan data berdasarkan
kolom tertentu, misal mengelompokkan data buku berdasarkan
id_penerbit. Klausa ini harus digunakan bersama fungsi agregasi seperti
COUNT() dan SUM(), karena untuk kolom yang tidak di kelompokkan, akan
diambil hanya satu data, perhatikan query berikut:
Hasil:
+-------------+--------------+
| id_penerbit | COUNT(judul) |
+-------------+--------------+
| 1 | 3 |
| 4 | 2 |
+-------------+--------------+
Dari hasil diatas diketahui bahwa terdapat 3 buku yang diterbitkan oleh
penerbit dengan id_penerbit 1, dan 2 buku oleh penerbit dengan
id_penerbit 4.
Selain dapat mengurutkan data dengan kriteria satu kolom, kita juga dapat
mengurutkan data dengan kriteria lebih dari satu kolom. Pada model
pengurutan ini, data akan diurutkan mulai dari kolom paling kiri yang ada
pada klausa ORDER BY, misal kita urutkan data berdasarkan tanggal terbit
dan judul, jalankan query berikut:
Penjelasan:
Hasil:
+---------+------------------------------------+------------+
| id_buku | judul | tgl_terbit |
+---------+------------------------------------+------------+
| 4 | Kumpulan Aplikasi PHP untuk Pemula | 2016-02-25 |
| 3 | MySQL Untuk Pemula | 2014-11-28 |
+---------+------------------------------------+------------+
Pada contoh diatas, karena tidak ada data tgl_terbit yang sama, maka tidak
dilakukan pengurutan pada kolom judul.
8.7. HAVING
Sebelumnya, kita telah membahas tentang klausa WHERE, nah, klausa
HAVING ini sama seperti klausa WHERE, bedanya:
1. Klausa WHERE hanya dapat digunakan pada kolom riil pada tabel,
sedangkan klausa HAVING dapat digunakan baik kolom riil tabel
Hasil:
+-----------------------------------------+------------+
| judul | tgl_terbit |
+-----------------------------------------+------------+
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 |
| Kumpulan Aplikasi PHP untuk Pemula | 2016-02-25 |
+-----------------------------------------+------------+
Pada query diatas, klausa HAVING dapat diganti dengan klausa WHERE,
keduanya akan menghasilkan output yang sama.
Pada contoh kali ini, kita akan menampilkan judul buku, harga, nilai diskon
( 10% dari harga buku ), dan harga buku setelah diskon. Selanjutnya,
dengan klausa HAVING kita ambil data buku yang memiliki harga setelah
diskon diatas 50.000, querynya adalah:
1. SELECT judul,
2. harga,
3. ROUND(0.1 * harga) AS diskon,
4. harga - ROUND(harga * 0.1) AS harga_diskon
Hasil:
+-----------------------------------------+-------+--------+--------------+
| judul | harga | diskon | harga_diskon |
+-----------------------------------------+-------+--------+--------------+
| Pemrograman Database Menggunakan MySQL | 59000 | 5900 | 53100 |
| PHP dan MySQL Langkah Demi Langkah + CD | 75000 | 7500 | 67500 |
| Mahir Dalam 7 Hari: Coreldraw X6 | 68000 | 6800 | 61200 |
+-----------------------------------------+-------+--------+--------------+
Pada contoh diatas klausa HAVING diterapkan pada kolom alias yaitu
harga_diskon, jika menggunakan klausa WHERE maka query akan
berbentuk seperti berikut:
1. SELECT judul,
2. harga,
3. ROUND(0.1 * harga) AS diskon,
4. harga - ROUND(harga * 0.1) AS harga_diskon
5. FROM buku1
6. WHERE harga - ROUND(harga * 0.1) > 50000
Pada contoh diatas terlihat bahwa pada klausa WHERE kita harus menulis
ulang formula penghitungan harga_diskon, hal ini karena klausa WHERE
tidak mengenali kolom alias.
Seperti pembahasan kita tentang klausa GROUP BY, kali ini kita akan
mengambil data jumlah buku yang dikelompokkan berdasarkan
id_penerbit, namun dengan jumlah buku kurang dari 3
Hasil:
+-------------+-------------+
| id_penerbit | jumlah_buku |
Pada query diatas, kita menggunakan kolom alias pada having, jika
menggunakan nama kolom, klausa having dapat kita ubah menjadi HAVING
COUNT(judul) < 3. Karena dijalankan setelah klausa GROUP BY, maka kita
tidak dapat mengganti HAVING dengan WHERE
8.8. LIMIT
Sejauh ini, kita telah berhasil menampilkan data berdasarkan kriteria
tertentu menggunakan klausa WHERE, namun, data yang ditampilkan tidak
terbatas, semuanya ditampilkan. Untuk keperluan tertentu, kita perlu
untuk membatasi banyaknya data yang diambil, misal menampilkan 10
buku terbaru. Untuk keperluan tersebut, kita gunakan klausa LIMIT.
Perhatikan bahwa kali ini kita menggunakan tabel buku, bukan buku1.
Tabel ini berisi lebih banyak data, tabel ini telah disertakan pada file SQL
buku ini. Hasil yang kita peroleh:
+-----------------------------------------+------------+
| judul | tgl_terbit |
+-----------------------------------------+------------+
| Pemrograman Database Menggunakan MySQL | 2016-00-00 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2016-00-00 |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 |
+-----------------------------------------+------------+
Pada contoh diatas, untuk mengambil data mulai baris ke-4, kita
menggunakan offset 3 bukan 4, karena index baris dimulai dari 0
(0,1,2,3…), sehingga, baris ke 4 bernilai 3.
MySQL akan memfilter data sehingga yang diambil adalah data buku
dengan id_penerbit 1, kemudian, MySQL menyimpan data tersebut ke
dalam temporary tabel (klausa WHERE)
Tabel pengarang:
Tabel penerbit:
Hasil:
+-----------------------------------------+------------+--------------------+----------------+
| judul | tgl_terbit | nama | nama |
+-----------------------------------------+------------+--------------------+----------------+
| Desain Grafis dengan Powerpoint | 2016-08-29 | Jubilee Enterprise | Jubilee |
| Otodidak Membuat Blog dengan Blogger | 2016-02-29 | Jubilee Enterprise | Jubilee |
| Kumpulan Aplikasi PHP untuk Pemula | 2016-02-25 | Jubilee Enterprise | Jubilee |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 | R. H. Sianipar | Andi Publisher |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2016-00-00 | Madcoms | Andi Publisher |
+-----------------------------------------+------------+--------------------+----------------+
8.10. Alias
Pada contoh contoh sebelumnya, terlihat bahwa data yang ditampilkan ke
user selalu berbentuk tabel dengan nama kolom sesuai dengan nama yang
kita definisikan dalam klausa SELECT. Pada kondisi tertentu, kita perlu
mengubah nama kolom hasil query agar tabel hasil query tersebut dapat
diolah lebih lanjut dengan mudah, seperti ditampilkan dalam web
menggunakan PHP, nama kolom baru ini disebut kolom alias.
Selain pada kolom, ketika query dijalankan kita juga dapat mengubah nama
tabel, perubahan nama tabel ini sifatnya hanya sementara, saat query
dijalankan saja. Hal ini hanya untuk memudahkan agar query lebih mudah
ditulis dan dibaca, terutama jika query yang ditulis panjang.
Contoh:
Sama seperti pada kolom alias, kita juga dapat mengabaikan penggunaan
AS, sehingga kode yang kita tulis menjadi:
Pada MySQL, terdapat tiga jenis operator yang didukung yaitu: operator
aritmetika (aritmethic operator), operator pembanding (comparison
operator), dan operator logika (logical operator). Pada bagian ini kita akan
membahas ketiga jenis operator tersebut.
2 / Operator pembagian
5 + Operator Penjumlahan
6 * Operator Perkalian
Kita semua pasti sudah familiar dengan operator +, -, * m dan /, yang masih
asing mungkin operator DIV dan (% atau MOD).
SELECT 2 * 3 + 4 / 2
SELECT 2 * (3 + 4) / 2
Hasil:
+-----------------------------------------+-------+--------+
| judul | harga | markup |
+-----------------------------------------+-------+--------+
| Pemrograman Database Menggunakan MySQL | 59000 | 60000 |
| PHP dan MySQL Langkah Demi Langkah + CD | 75000 | 76000 |
| MySQL Untuk Pemula | 34800 | 35800 |
+-----------------------------------------+-------+--------+
Hasil:
+-----------------------------------------+-------+-------------+
| judul | harga | harga_minus |
+-----------------------------------------+-------+-------------+
| Pemrograman Database Menggunakan MySQL | 59000 | -59000 |
| PHP dan MySQL Langkah Demi Langkah + CD | 75000 | -75000 |
| MySQL Untuk Pemula | 34800 | -34800 |
+-----------------------------------------+-------+-------------+
Jika kolom yang kita tambahkan tanda minus memiliki tipe data selain
numeric, maka akan dihasilkan nilai -0.
Fungsi kedua dari tanda minus ini adalah sebagai operator pengurangan.
Misal kita ingin menampilkan data judul, harga, diskon sebesar Rp. 1.100,
dan harga setelah diskon, query yang kita jalankan:
Pada query diatas, untuk menerapkan persentase diskon, kita tidak dapat
menggunakan tanda persen, melainkan harus kita ubah ke dalam format
desimal.
Sebagai contoh misal data pada tabel buku1 adalah sebagai berikut:
Hati hati, pada contoh diatas, stok dengan nilai 2 akan menghasilkan nilai
0, demikian juga dengan stok yang kosong (nilai stok 0), namun pada stok
yang nilainya 1, akan menghasilkan nilai 1.
Operator MOD
Fungsi MOD
Pada contoh diatas, stok yang jumlahnya kurang dari dua akan
menghasilkan nilai 0
Operator Keterangan
Contoh: jika nilai yang kita bandingkan berupa string (teks) namun isi
string tersebut berupa numeric/angka maka MySQL akan mengubahnya
menjadi numeric.
Berdasarkan kriteria diatas, jika kita ingin mencari buku dengan tanggal
terbit 2016-00-00, kita dapat menjalankan query berikut:
Contoh lain kita ambil data dengan kriteria id_penerbit = 1 dan tahun terbit
lebih besar atau sama dengan 2016
Hasil:
+-----------------------------------------+------------+-------------+
| judul | tgl_terbit | id_penerbit |
+-----------------------------------------+------------+-------------+
| Pemrograman Database Menggunakan MySQL | 2016-00-00 | 1 |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 | 1 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2016-00-00 | 1 |
+-----------------------------------------+------------+-------------+
Nah, untuk membuat output sesuai yang kita harapkan, kita harus
mengelompokkan operator menggunakan tanda kurung, karena semua
yang ada di dalam tanda kurung memiliki prioritas lebih dibanding yang
lain termasuk operator AND. Selanjutnya, mari kita perbaiki query dengan
menambahkan tanda kurung:
Hasil:
+-----------------------------------------+------------+-------------+
| judul | tgl_terbit | id_penerbit |
+-----------------------------------------+------------+-------------+
| Desain Grafis dengan Powerpoint | 2016-08-29 | 4 |
| Otodidak Membuat Blog dengan Blogger | 2016-02-29 | 4 |
| Kumpulan Aplikasi PHP untuk Pemula | 2016-02-25 | 4 |
| Pemrograman Database Menggunakan MySQL | 2016-00-00 | 1 |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 | 1 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2016-00-00 | 1 |
+-----------------------------------------+------------+-------------+
9.4. Operator IN
Operator IN digunakan untuk membandingkan data yang ada pada kolom
tertentu dengan sekelompok nilai yang telah ditentukan. Adapun syntax
yang digunakan adalah:
SELECT kolom
FROM tabel
WHERE kolom IN (nilai1, nilai2, nilai3, ...)
Jika kita perhatikan operator IN ini sama dengan operator OR, bedanya
penulisannya lebih ringkas, dimana kita tidak perlu menuliskan nama field
berulangkali, dan secara internal, ketika menjalankan operator IN, MySQL
akan mengubahnya menjadi OR, jadi, bisa di katakan bahwa operator IN
merupakan alias dari operator OR.
Pada query diatas, jika kita ubah menjadi OR, klausa WHERE menjadi WHERE
id_penerbit = 1 OR id_penerbit = 3 OR id_operator = 4
SELECT kolom
FROM tabel
WHERE kolom BETWEEN nilai_minimum AND nilai_maksimum
Penting diperhatikan bahwa kriteria tersebut akan cocok dengan data yang
memiliki nilai sama dengan nilai_minimum dan nilai_maksimum. Jika
dibuat dalam bentuk operator pembanding, maka akan berbentuk seperti
query berikut:
SELECT kolom
FROM tabel
WHERE kolom >= nilai_minimum AND kolom <=
nilai_maksimum
Contoh lain kita ambil data buku yang memiliki rentang harga 25000 s.d
50000
Hasil:
+--------------------------------------+-------+
| judul | harga |
+--------------------------------------+-------+
| Buku Sakti Wordpress | 49800 |
| Ide Bisnis Bermodal Blog | 49800 |
| Desain Grafis dengan Powerpoint | 46800 |
| Otodidak Membuat Blog dengan Blogger | 39800 |
| Jago Wordpress | 39800 |
+--------------------------------------+-------+
Hasil:
+------------------------------------+-------------+------------+
| judul | id_penerbit | tgl_terbit |
+------------------------------------+-------------+------------+
| MySQL Untuk Pemula | 4 | 2014-11-28 |
| Kumpulan Aplikasi PHP untuk Pemula | 4 | 2016-02-25 |
| Blogger untuk Pemula | 3 | 2015-06-15 |
| Ide Bisnis Bermodal Blog | 3 | 2014-12-08 |
| Jago Wordpress | 3 | 2014-11-03 |
+------------------------------------+-------------+------------+
Operator NOT ini sering digunakan bersama dengan operator IN. Contoh
kita ambil data buku dengan id_penerbit selain 1, 3, dan 4
Hasil:
+----------------------------------------------+------------+-------------+
| judul | tgl_terbit | id_penerbit |
+----------------------------------------------+------------+-------------+
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 2015-12-22 | 5 |
| Cara Efektif Belajar Framework Laravel | 2015-04-15 | 5 |
| Framework PHP Yii 2 | 2016-00-00 | 7 |
+----------------------------------------------+------------+-------------+
Contoh lain kita ambil data buku yang terbit di luar bulan Juni s.d Desember
2016
Hasil:
Wildcard %
Wildcard % dapat diletakkan dimana saja di dalam teks yang dicari baik di
depan, tengah, maupun belakang, dan dapat digunakan lebih dari satu kali.
mari kita bahas satu per satu dengan contoh.
Contoh 1: kita akan mencari judul buku yang mengandung kata depan
MySQL, query yang kita jalankan:
Hasil:
+----------------------------------------------+------------+
| judul | tgl_terbit |
+----------------------------------------------+------------+
| Pemrograman Database Menggunakan MySQL | 2016-00-00 |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 2015-12-22 |
+----------------------------------------------+------------+
Contoh 3: Kita cari judul buku yang mengandung kata MySQL, query yang
kita jalankan:
Hasil:
+----------------------------------------------+------------+
| judul | tgl_terbit |
+----------------------------------------------+------------+
| Pemrograman Database Menggunakan MySQL | 2016-00-00 |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 |
| MySQL Untuk Pemula | 2014-11-28 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2016-00-00 |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 2015-12-22 |
| Pemrograman Stored Procedure Pada MySQL + cd | 2015-00-00 |
+----------------------------------------------+------------+
Contoh 4: Kita cari judul buku yang mengandung kata MySQL dan Pemula,
query yang kita jalankan:
Hasil:
Wildcard _
Contoh 1: kita cari judul buku yang mengandung kata MySQL maupun
MSSQL, maka query yang kita gunakan:
Contoh lain kita akan mencari kata yang terdiri dari 5 karakter, dimana 3
karakter paling belakang adalah SQL
Kriteria diatas akan cocok dengan kata PQSQL, MSSQL, DBSQL, dst.
Hasil:
+-------------------------------------------------------+------------+
| judul | tgl_terbit |
+-------------------------------------------------------+------------+
| Pemrograman Database Menggunakan MySQL | 2016-00-00 |
| PHP dan MySQL Langkah Demi Langkah + CD | 2016-00-00 |
| Kumpulan Aplikasi PHP untuk Pemula | 2016-02-25 |
| Blogger untuk Pemula | 2015-06-15 |
| Ide Bisnis Bermodal Blog | 2014-12-08 |
| ... | ... |
+-------------------------------------------------------+------------+
Pada contoh diatas, data telp PT. Elex Media Komputindo bernilai NULL,
sedangkan pada Jubilee berisi string kosong '', selanjutnya, kita cari data
penerbit yang data nomor teleponnya nya kosong dengan menjalankan
query berikut:
Pada contoh diatas terlihat bahwa hanya Jubilee yang cocok dengan query
yang kita jalankan. Untuk menguji apakah suatu kolom bernilai NULL, kita
harus menggunakan IS NULL. Mari kita perbaiki query dengan
menggunakan IS NULL
Hasil:
+---------------------------+------+
| nama | telp |
+---------------------------+------+
| PT. Elex Media Komputindo | NULL |
| Jubilee | |
+---------------------------+------+
Seperti operator lain, kita juga dapat menggunakan operator NOT untuk
membalik kondisi, sehingga untuk mencari kolom yang tidak mengandung
nilai NULL, kita gunakan IS NOT NULL, misal:
Hasil:
Pada praktiknya, sebuah database terdiri dari banyak tabel, bahkan ada
yang hingga ratusan tabel, hal tersebut terkadang memang diperlukan agar
prinsip prinsip pengelolaan database yang baik dapat tetap terjaga seperti
integritas dan konsistensi data.
Identifikasi primary key dan foreign key dari tabel yang akan kita
gabungkan. Primary key adalah field kunci yang unik yang yang
membedakan tiap row dari suatu tabel. Sedangkan foreign key adalah
field pada tabel lain yang menjadi referensi dari primary key, artinya
nilai foreign key pada tabel tersebut berasal dari nilai primary key
tabel lain. Tidak seperti primary key, foreign key tidak harus unik,
dalam satu tabel beberapa row bisa memiliki key yang sama.
Dalam join tabel, primary key dan foreign key tidak harus ada, namun
dengan adanya kedua key tersebut akan sangat memudahkan dalam
menggabungkan tabel.
buku penerbit
Misal kita tampilkan semua data buku hanya yang ada data penerbitnya.
Perintah SQL yang kita jalankan:
Klausa INNER JOIN dapat diganti dengan CROSS JOIN, atau cukup
dengan JOIN saja, ketiganya akan menghasilkan output yang sama.
Pada buku ini, kita akan selalu menggunakan klausa JOIN tanpa
tambahan INNER atau CROSS.
OUTER JOIN ini dibagi menjadi tiga yaitu LEFT OUTER JOIN, RIGHT OUTER
JOIN, dan FULL OUTER JOIN, namun, sampai dengan saat ini, MySQL hanya
men-support LEFT OUTER JOIN dan RIGHT OUTER JOIN.
Contoh 1: Misal kita tampilkan semua data judul buku beserta nama
penerbitnya. Perintah SQL yang kita jalankan:
Seperti yang telah kita pelajari pada bab sebelumnya, kita dapat menguji
nilai NULL dengan klausa IS NOT NULL, melanjutkan contoh query diatas,
mari kita hilangkan data buku yang nama penerbitnya bernilai NULL, kita
ubah query menjadi:
Jika query tersebut dijalankan, hasil yang diperoleh sama seperti contoh
ketika kita menggunakan INNER JOIN/JOIN
Pada contoh sebelumnya hubungan antara tabel buku dan penerbit adalah
satu ke banyak ke satu (many to one) dimana satu judul buku hanya bisa
diterbitkan oleh satu penerbit (Gambar 10.3).
Pada kasus yang sering terjadi, hubungan antara tabel pertama dan kedua
adalah satu ke banyak (one to many) dimana data pada tabel pertama
terhubung ke banyak data pada tabel ke dua (Gambar 10.4).
Kolom id_buku pada tabel ini merupakan foreign key dari kolom id_buku
pada tabel buku.
buku penerbit
Misal kita tampilkan semua data penerbit beserta data buku yang
diterbitkan. Perintah SQL yang kita jalankan:
Seperti pada contoh LEFT JOIN, pada contoh diatas penulis menyingkat
RIGHT OUTER JOIN menjadi hanya RIGHT JOIN
Kebalikan dari LEFT JOIN, pada contoh diatas, untuk penerbit yang tidak
ada data bukunya, maka kolom judul akan bernilai NULL, seperti contoh
LEFT JOIN, kita dapat menghilangkan baris yang bernilai NULL dengan
klausa IS NOT NULL
buku penerbit
Sebagai contoh kita gabungkan data tabel buku dan data tabel penerbit
sebagai berikut:
Pada penggabungan model outer join seperti diatas, urutan tabel harus
diperhatikan karena MySQL akan menampilkan semua data tabel yang ada
di paling kiri. Hal ini tidak berlaku pada model INNER JOIN. Pada INNER
JOIN, MySQL akan menentukan sendiri tabel mana yang akan di proses
terlebih dahulu, prioritas tabel tergantung banyak faktor seperti primary
key, foreign key, index, dll
Jika query tersebut dijalankan maka tidak ada baris yang bernilai NULL
seperti yang terjadi pada contoh sebelumnya.
Terdapat cara lain agar penulisan menjadi lebih singkat yaitu mengganti
klausa ON dengan klausa USING(kolom). Syarat menggunakan klausa
USING adalah nama kolom yang digunakan pada klausa USING harus ada
pada kedua tabel. Pada contoh diatas, tabel buku dan penerbit sama sama
memiliki kolom id_penerbit, sehingga query diatas dapat kita ubah
menjadi:
Contoh 1: Penerapan pada OUTER JOIN. Pada contoh kali ini, kita
gabungkan tabel buku dengan tabel penulis dengan menambahkan klausa
NATURAL sebelum klausa LEFT JOIN atau RIGHT JOIN
Contoh 3 Penerapan pada OUTER JOIN dengan lebih dari satu tabel. Contoh
kali ini kita akan menggabungkan tabel buku, pengarang, dan penerbit
menggunakan NATURAL JOIN
Hasil :
+------------------------------------------+---------------+--------------------+
| judul | nama_penerbit | nama_pengarang |
+------------------------------------------+---------------+--------------------+
| Pemrograman Database Menggunakan MySQL | NULL | R. H. Sianipar |
| PHP dan MySQL Langkah Demi Langkah + CD | NULL | R. H. Sianipar |
| MySQL Untuk Pemula | NULL | Jubilee Enterprise |
| Kumpulan Aplikasi PHP untuk Pemula | NULL | Jubilee Enterprise |
| Pemrograman PHP Dan MySQL Untuk Pemula | NULL | Madcoms |
| ... | NULL | ... |
+------------------------------------------+---------------+--------------------+
Contoh kita akan menampilkan data buku, penerbit, dan url dari buku
tersebut, untuk itu gabungkan tabel buku dan tabel penerbit. Sejauh yang
telah kita pelajari, maka query yang akan kita jalankan adalah:
Namun ketika kita jalankan, kita akan mendapatkan pesan error sebagai
berikut:
Pesan error tersebut disebabkan karena MySQL tidak tahu field url pada
tabel mana yang harus digunakan, tabel buku atau tabel penerbit. Untuk itu
kita harus mendefinisikan nama tabel pada field url tersebut. Mari kita
ubah querynya menjadi:
Catatan:
Selanjutnya, kita akan menampilkan judul buku utama dan judul buku
referensi, query yang kita gunakan:
Pada contoh diatas, terdapat judul_ref yang bernilai NULL, hal ini karena
nilai pada kolom referensi tidak ada pada kolom id_buku.
Sampai sejauh ini, hasil yang kita peroleh sesuai dengan yang kita
harapkan, namun kita perlu berhati hati, terkadang, untuk alasan
kesederhanaan, kondisi yang seharusnya berada pada klausa WHERE, kita
definisikan pada pada klausa ON. Hal ini terkadang menghasilkan output
yang tidak diharapkan, untuk itu, sebaiknya hindari penggunaan cara
tersebut. Perhatikan beberapa contoh berikut
Hasil:
+-------------------------------------------+----------------+
| judul | nama_penerbit |
+-------------------------------------------+----------------+
| Pemrograman Database Menggunakan MySQL | Andi Publisher |
| PHP dan MySQL Langkah Demi Langkah + CD | Andi Publisher |
| MySQL Untuk Pemula | NULL |
| Kumpulan Aplikasi PHP untuk Pemula | NULL |
| Pemrograman PHP Dan MySQL Untuk Pemula | Andi Publisher |
| ... | ... |
+-------------------------------------------+----------------+
Pada contoh diatas, MySQL akan menampilkan semua data tabel yang ada
di sebelah kiri, yaitu tabel buku sedangkan untuk kolom penerbit, MySQL
Hal tersebut dikarenakan pada OUTER JOIN, yang pada contoh ini LEFT
JOIN, MySQL akan menampilkan semua data tabel yang ada di sebelah kiri
(tabel buku - yang ada pada klausa FROM), sedangkan untuk data yang ada
pada tabel di sebelah kanan (penerbit) MySQL akan memfilternya
menggunakan kondisi pada klausa ON
Pada contoh diatas, hasil yang kita peroleh sesuai dengan apa yang kita
harapkan. Hal ini disebabkan karena pada INNER JOIN, MySQL hanya akan
menampilkan data yang sesuai dengan kondisi pada klausa ON
Contoh 3: Gabungan INNER JOIN dan OUTER JOIN. Selanjutnya, mari kita
lanjutkan contoh query diatas dengan mendefinisikan kondisi pada klausa
WHERE. Jalankan query outer join berikut ini
Pada SQL, terdapat model lain untuk menjalankan query antar tabel yaitu
yang disebut implisit join. Disebut implisit join karena hubungan antar
tabel tidak didefinisikan dengan jelas, melainkan hanya dinyatakan dengan
kondisi pada klausa where.
Contoh kita tampilkan data judul dan data penerbit menggunakan model
implisit join
Pada model implisit join, kita hanya bisa melakukan INNER JOIN
(seperti pada query diatas) dan tidak bisa melakukan OUTER JOIN
seperti pada model eksplisit join.
Model implisit join ini juga sering disebut dengan istilah THETA STYLE
sedangkan model eksplisit join disebut juga ANSI STYLE. Model THEA
STYLE dibuat ketika awal standar SQL dibuat (sebelum versi 2), setelah
muncul standar SQL versi 2.0, mulailah digunakan klausa JOIN.
Pada BAB ini kita akan membahas berbagai statemen SQL untuk
memanipulasi data pada tabel baik menambahkan (INSERT), mengubah
(UPDATE), dan menghapus (DELETE). Statemen SQL untuk memanipulasi
data ini disebut Data Manipulation Language (DML)
Hasilnya adalah:
Pada contoh diatas, data pada klausa VALUES akan dimasukkan sesuai
dengan urutan kolom.
1. Agar data yang dimasukkan sesuai dengan kolom yang ada, kita harus
ingat urutan kolom.
2. Harus mendefinisikan data untuk semua kolom, jika ada satu saja yang
terlewat, maka akan terjadi error.
3. Terikat dengan struktur tabel, jika strukturnya berubah, misal urutan
kolom atau ada penambahan kolom, maka kita harus mengubah
statement INSERT yang telah kita buat.
Jika kolom memiliki constraint NOT NULL dan tidak memiliki nilai
default maka jika tidak didefinisikan, akan muncul pesan error
Error diatas terjadi karena kolom total_trx memiliki atribut NOT NULL
tetapi tidak memiliki nilai default.
Selain tidak mendefinisikan nama kolom, nilai default juga dapat diperoleh
dengan memberi klausa DEFAULT pada VALUES, misal:
Cek hasilnya:
Pada contoh diatas, fungsi NOW() akan menghasilkan waktu sekarang, yaitu
2017-03-14 17:48:41
Pada kedua contoh diatas, data diperoleh dari hasil query pada tabel lain.
Perlu diperhatikan bahwa, kita tidak bisa menggunakan data pada tabel
yang akan dimasukkan datanya, misal, kita akan menambahkan data pada
tabel penjualan_rekap dengan hasil akhir sebagai berikut:
+----------+------------+---------------------+-----------+
| id_rekap | tgl_trx | tgl_rekap | total_trx |
+----------+------------+---------------------+-----------+
| 1 | 2017-03-14 | 2017-03-14 17:35:37 | 410000 |
| 2 | 2017-03-05 | 2017-03-14 17:48:41 | 150000 |
| 3 | 2017-03-12 | 2017-03-14 17:48:41 | 150000 |
+----------+------------+---------------------+-----------+
Hasilnya:
Ketika memasukkan data dalam jumlah besar dan terjadi error, maka data
sebelumnya tetap masuk, misal, pada contoh diatas, ketika terjadi error
pada data ke tiga, maka data pertama dan kedua tetap masuk. Untuk
memastikan semua data berhasil dimasukkan atau tidak sama sekali,
gunakan Transaksi yang dibahas pada BAB 24 Transaksi
Kelemahan model ini adalah kita bisa saja melewatkan kolom tertentu
yang tidak memiliki nilai default, disamping itu kita tidak dapat
menggunakan model ini untuk memasukkan data lebih dari satu baris.
Pada kolom dengan tipe data numeric, jika data yang dimasukkan
melebihi batas maksimal nilai dari tipe data yang digunakan, maka
akan digunakan nilai maksimal dari tipe data tersebut. Misal kolom
dengan tipe data TINYINT, dimana batas maksimalnya adalah 124,
maka ketika diisi dengan 250, nilai yang masuk adalah 124.
Pada kolom dengan tipe data karakter, jika data yang dimasukkan
melebihi batas maksimal nilai dari tipe data yang digunakan, maka teks
akan terpotong. Misal kolom dengan tipe data CHAR(5), ketika diisi
dengan string 'jakarta', maka yang masuk adalah 'jakar'. Hal in juga
berlaku untuk tipe data text yang dapat menampung maksimal 65.535
karakter.
Jika tipe data kolom adalah numeric, maka jika kita tidak bisa
memasukkan data kombinasi numeric dan non numeric, seperti '17a',
jika tidak, maka akan muncul pesan error:
Jika kita jalankan kembali statemen yang sama, maka kita akan
memperoleh hasil sebagai berikut:
Dari informasi diatas terlihat bahwa query cocok pada semua baris, namun
tidak ada data yang diubah, karena semua data pada kolom nama sudah
berupa huruf kapital.
Jika suatu kolom memiliki nilai default, maka jika kita update nilai kolom
tersebut dengan nilai DEFAULT, maka nilai kolom tersebut akan berubah
menjadi nilai defaultnya, misal, kita memiliki tabel penjualan dengan data
sebagai berikut:
Selanjutnya kita update semua kolom pada tgl_trx dengan memberi nilai
DEFAULT
Query diatas mengubah data kolom tgl_trx yang memiliki nilai tanggal
sekarang, yaitu 2017-03-15 dengan jam berapapun, menjadi tanggal 2017-
05-03. Fungsi DATE() berfungsi mengambil tanggal dari kolom tgl_trx,
selanjutnya hasilnya dibandingkan dengan tanggal sekarang DATE(NOW()).
Kebetulan semua data memiliki tanggal yang sama sehingga ketiganya
diupdate.
Selanjutnya kita update kolom diskon dengan memberi nilai 0.1 (10%)
dan kita sesuaikan nilai pada kolom total_neto menjadi harga setelah
diskon
Pada query diatas, MySQL akan memeriksa baris satu per satu. Pertama
tama MySQL akan mengubah nilai pada kolom diskon menjadi 0.1,
selanjutnya mengubah nilai pada kolom total_neto dengan mengalikan
nilai pada kolom total_trx dengan nilai pada kolom diskon (total_trx
* diskon) kemudian hasilnya dikurangkan dengan nilai pada kolom
total_trx yaitu total_trx - (total_trx * diskon)
Hasilnya adalah:
Selanjutnya kita akan mengupdate kolom total_trx yang ada pada tabel
penjualan berdasarkan nilai pada kolom total yang ada pada tabel
penjualan_detail. Nilai kolom total tersebut di kelompokkan menjadi
satu berdasarkan id_trx yang sama. Setelah mengupdate nilai pada kolom
total_trx pada tabel penjualan, selanjutnya kita sesuaikan nilai pada
kolom total_neto.
1. UPDATE penjualan
2. SET total_trx = ( SELECT SUM(total)
3. FROM penjualan_detail
4. WHERE id_trx = penjualan.id_trx
5. ),
6. total_neto = total_trx - ( total_trx * diskon )
Jika berhasil, maka tabel penjualan akan tampak seperti tabel berikut:
Penjelasan:
Pada query diatas, karena tidak ada klausa WHERE atau LIMIT, MySQL akan
memeriksa satu persatu baris pada tabel penjualan, kemudian pada setiap
baris yang diperiksa, MySQL akan menjalankan statemen:
1. SELECT SUM(total)
2. FROM penjualan_detail
3. WHERE id_trx = penjualan.id_trx
Ketika berada pada baris pertama, query akan berbentuk seperti ini:
1. SELECT SUM(total)
2. FROM penjualan_detail
3. WHERE id_trx = 1
+------------+
| SUM(total) |
+------------+
| 35000 |
+------------+
1. UPDATE penjualan
2. SET total_trx = 35000,
3. total_neto = total_trx - ( total_trx * diskon )
Jika kita ingin menghapus baris tertentu pada suatu tabel, pastikan data
yang digunakan pada klausa WHERE bernilai unik, seperti data pada kolom
primary key, hal ini untuk memastikan tidak ada baris lain yang ikut
terhapus.
DELETE
FROM nama_tabel1, nama_tabel2
USING tabel_referensi
[WHERE ...]
Pada statemen diatas, data pada tabel yang berada setelah klausa FROM dan
sebelum klausa USING akan dihapus. Sebagai contoh, misal kita akan
menghapus data pada tabel penjualan dan penjualan_detail yang
memiliki id_trx = 2. Query yang kita jalankan adalah:
1. DELETE
2. FROM penjualan, penjualan_detail
3. USING penjualan JOIN penjualan_detail
4. WHERE penjualan.id_trx = 2
5. AND penjualan.id_trx = penjualan_detail.id_trx
Penulisan statemen DELETE model ini memang agak rumit dan berisiko,
terutama pada klausa USING dimana tabel referensi didefinisikan, untuk itu
kita harus berhati hati, jika tidak yakin, kita dapat menjalankan beberapa
statemen DELETE untuk masing masing tabel. Selain itu, statemen model ini
juga dapat digantikan dengan penggunaan FOREIGN KEY constrain yang
dibahas pada BAB 7 Constraint.
Dengan statemen DELETE, MySQL akan menghapus baris satu per satu,
sehingga memakan waktu lama terutama jika tabel tersebut berisi banyak
data. Sedangkan dengan statemen TRUNCATE, MySQL akan menghapus
tabel tersebut (drop) dan membuatnya kembali, sehingga waktu eksekusi
menjadi lebih cepat.
Selain lebih cepat dalam menghapus semua data, nilai pada kolom dengan
atribut AUTO_INCREMENT akan direset menjadi 1, sehingga ketika kita
masukkan data pada kolom tersebut, data yang dimasukkan bernilai 1. Hal
ini tidak terjadi jika kita menggunakan statemen DELETE FROM, meskipun
tabel telah kosong, nilai AUTO_INCREMENT akan tetap berlanjut dari nilai
terakhir yang digunakan.
Perlu diperhatikan jika terdapat trigger yang melibatkan tabel yang ingin
dikosongkan, maka statemen TRUNCATE tidak memicu trigger, sebaliknya,
dengan statemen DELETE, karena penghapusan dilakukan per-baris, maka
trigger akan aktif.
Pada BAB ini, kita akan membahas beberapa fungsi yang paling sering
digunakan, diantaranya fungsi terkait karakter, angka, tanggal dan
konversi nilai. Disamping itu, kita juga akan membahas tentang fungsi
komposit (composite function) atau fungsi di dalam fungsi.
Berdasarkan cara kerjanya, fungsi dibagi menjadi dua, yaitu scalar dan
agregat. Istilah skalar berasal dari matematika yang artinya operasi
dilakukan pada satu buah nilai. Dalam konteks tabel database, fungsi ini
hanya melibatkan nilai pada sebuah kolom. Sebagai contoh fungsi LTRIM
akan menghilangkan spasi yang ada di sebelah kiri suatu nilai.
Penjelasan:
Fungsi selalu disertai dengan tanda kurung buka dan kurung tutup
baik ada atau tidak ada argumen. Tanda kurung ini menandakan
bahwa ekspresi tersebut merupakan fungsi.
Antara nama fungsi dengan kurung buka dapat diberi jarak atau spasi,
misal NAMAFUNGSI (), namun demikian, beberapa fungsi tidak
memperbolehkan adanya spasi tersebut.
Untuk lebih mudahnya fungsi yang kita bahas disini akan mengambil data
dari tabel buku yang berisi data sebagai berikut:
+---------+-------------------------+--------------+-------------+------------+-------+
| id_buku | judul | id_pengarang | id_penerbit | tgl_terbit | harga |
+---------+-------------------------+--------------+-------------+------------+-------+
| 1 | Pemrograman Database ...| 1 | 1 | 16/01/2016 | 59000 |
| 2 | PHP dan MySQL Langkah...| 1 | 1 | 16/01/2016 | 75000 |
| 3 | MySQL Untuk Pemula ...| 3 | 4 | 28/11/2014 | 34800 |
| 4 | Kumpulan Aplikasi PHP...| 3 | 4 | 25/02/2016 | 34800 |
| 5 | Mahir Dalam 7 Hari: C...| 4 | 1 | 01/01/2013 | 68000 |
+---------+-------------------------+--------------+-------------+------------+-------+
Fungsi diatas menerima dua argumen yaitu teks dan jumlah huruf yang
diambil, kedua argumen ini bersifat mandatory (wajib ada).
Salah satu contoh penggunaan fungsi ini adalah ketika kita mengambil data
tanggal yang berbentuk string. Misal kita akan mengambil data buku
berdasarkan tanggal terbit:
Sama seperti fungsi LEFT, fungsi RIGHT juga menerima dua argumen.
Kedua argumen ini wajib diisi, jika tidak, maka akan muncul pesan error.
Pada query diatas, kita mengambil 4 karakter dari kolom tgl_terbit mulai
dari kanan, sehingga kita peroleh data tahun terbit.
Namun, ketika kita jalankan query diatas, maka hasil yang kita peroleh:
Argumen kedua tidak boleh diisi angka nol (0), namun boleh diisi
bilangan positif atau negatif. Jika positif, maka karakter dihitung dari
depan (kiri), jika negatif, karakter dihitung mulai dari belakang
(kanan)
Contoh 1:
Hasil:
+-------+
| Hasil |
+-------+
| cd |
+-------+
Pada contoh diatas, kita mengambil karakter mulai dari karakter ketiga,
yaitu c dan diambil sebanyak 2 karakter, sehingga menghasilkan cd
Contoh 2:
Hasil:
+-------+
| Hasil |
+-------+
| cde |
+-------+
Karena argumen ketiga kita kosongkan, maka akan diambil semua karakter
yang tersisa, sehingga menghasilkan cde.
Contoh 3:
Hasil:
+-------+
| Hasil |
+-------+
| cd |
+-------+
Pada contoh diatas, karakter awal dihitung mulai dari karakter terakhir
sebanyak 3 karakter (-3) yaitu huruf c, selanjutnya diambil sebanyak 2
Contoh 5:
Hasil:
+-------+
| Hasil |
+-------+
| cde |
+-------+
Karena argumen ketiga kosong, maka diambil semua karakter yang tersisa.
Perhatikan bahwa hasil yang kita peroleh sama seperti pada Contoh 2
TRIM:
TRIM(teks)
LTRIM:
LTRIM(teks)
RTRIM:
RTRIM(teks)
Contoh TRIM:
Contoh LTRIM:
Contoh RTRIM:
UPPER(teks)
Fungsi UPPER dan LOWER hanya menerima satu argumen teks yang wajib
diisi. Misal, kita tampilkan judul buku dengan huruf besar semua. Query
yang kita jalankan:
Hasil:
+-----------------------------------------+
| judul_uppper |
+-----------------------------------------+
| PEMROGRAMAN DATABASE MENGGUNAKAN MYSQL |
| PHP DAN MYSQL LANGKAH DEMI LANGKAH + CD |
| MYSQL UNTUK PEMULA |
+-----------------------------------------+
Contoh:
Untuk penerapan pada tabel, misal kita gabungkan kolom judul dan harga,
query yang kita jalankan:
Hasil:
+---------+--------------------------------------------------------------+
| id_buku | Buku |
+---------+--------------------------------------------------------------+
| 1 | Judul: Pemrograman Database Menggunakan MySQL, Harga: 59000 |
| 2 | Judul: PHP dan MySQL Langkah Demi Langkah + CD, Harga: 75000 |
| 3 | Judul: MySQL Untuk Pemula, Harga: 34800 |
| 4 | Judul: Kumpulan Aplikasi PHP untuk Pemula, Harga: 34800 |
| 5 | Judul: Mahir Dalam 7 Hari: Coreldraw X6, Harga: 68000 |
+---------+--------------------------------------------------------------+
Ketika menjalankan fungsi CONCAT, MySQL akan mengubah tipe data pada
semua argumen menjadi string. Pada contoh diatas, kolom harga memiliki
tipe data INT, oleh MySQL diubah menjadi string.
Jika salah satu argumen bernilai NULL, maka hasil penggabungan akan NULL,
misal:
Hasil:
Pada contoh diatas, karena argumen harga bernilai NULL, maka semua
hasil menjadi NULL. Contoh lain:
1. SELECT id_buku,
2. CONCAT(
3. 'Judul: ', judul,
4. ', Harga: ', IF(harga > 50000, harga, NULL)
5. ) AS Buku
6. FROM buku
Hasil:
+---------+--------------------------------------------------------------+
| id_buku | Buku |
+---------+--------------------------------------------------------------+
| 1 | Judul: Pemrograman Database Menggunakan MySQL, Harga: 59000 |
| 2 | Judul: PHP dan MySQL Langkah Demi Langkah + CD, Harga: 75000 |
| 3 | NULL |
| 4 | NULL |
| 5 | Judul: Mahir Dalam 7 Hari: Coreldraw X6, Harga: 68000 |
+---------+--------------------------------------------------------------+
Pada contoh diatas, jika harga buku dibawah 50.000, kita ubah harganya
menjadi NULL, sehingga fungsi CONCAT pada buku dengan ID 3 dan 4
menghasilkan nilai NULL.
Hasil:
Hasil:
+------------------------------+
| CONCAT_WS(NULL, 'Nilai', 95) |
+------------------------------+
| NULL |
+------------------------------+
Namun jika argumen kedua dan setelahnya ada yang bernilai NULL, maka
MySQL akan tetap memprosesnya dan nilai NULL akan dilewati, contoh:
Hasil:
+------------------------------------+
| CONCAT_WS(': ', 'Nilai', NULL, 95) |
+------------------------------------+
| Nilai: 95 |
+------------------------------------+
Untuk penerapan pada tabel, misal kita gabung semua kolom yang ada
pada tabel buku dengan spasi sebagai separator:
Hasil:
Dalam praktek, salah satu penerapan fungsi ini adalah ketika kita ingin
membuat file CSV, misal kita buat data CSV dengan separator koma,
jalankan query berikut:
Hasil:
+----------------------------------------------------------+
| buku |
+----------------------------------------------------------+
| Pemrograman Database Menggunakan MySQL,16/01/2016,59000 |
| PHP dan MySQL Langkah Demi Langkah + CD,16/01/2016,75000 |
| MySQL Untuk Pemula,28/11/2014,34800 |
| Kumpulan Aplikasi PHP untuk Pemula,25/02/2016,34800 |
| Mahir Dalam 7 Hari: Coreldraw X6,01/01/2013,68000 |
+----------------------------------------------------------+
Sebagai contoh, pada pembahasan fungsi RIGHT, tanggal terbit pada judul
buku "Pemrograman Database Menggunakan MySQL" adalah
"10/03/2017 " dimana terdapat tambahan spasi di belakang tanggal,
sehingga ketika mengambil data tahun menggunakan fungsi
RIGHT(tanggal, 4) akan diperoleh hasil "017 ". Untuk dapat
menghasilkan 2017, maka sebelum kita jalankan fungsi RIGHT, kita
1. SELECT judul,
2. RIGHT(RTRIM(tgl_terbit), 4) AS tahun
3. FROM buku
4. WHERE id_buku = 1
SELECT NOW();
Karena fungsi ini tidak memiliki argumen, kita tidak dapat mengatur
output dari tanggal yang dihasilkan. Pada contoh diatas, dihasilkan 2016-
03-17 06:05:56 berarti tanggal (date) 17 Maret 2017 dan waktu (time)
pukul 06 menit ke 05 dan detik ke 56. Perhatikan bahwa tanggal tersebut
berformat YYYY-MM-DD HH:MM:SS yang merupakan format tanggal/waktu
standar SQL.
SELECT CURDATE();
Hasil:
+------------+
| CURDATE() |
+------------+
| 2017-04-06 |
+------------+
Fungsi DATE_FORMAT() memiliki dua argumen yang wajib diisi yaitu (1)
date yang berisi data tanggal yang ingin diolah, dan (2) format yang berisi
format output yang diinginkan. Format penulisan fungsi ini adalah:
DATE_FORMAT(tanggal, format_tanggal)
Format Deskripsi
Hari
%a Nama hari dalam satu minggu dalam tiga huruf (Sun s.d Sat)
%W Nama hari dalam satu minggu (Sunday s.d Saturday)
Hari dalam satu minggu berbentuk angka (0 = Minggu, 6 =
%w
Sabtu)
%d Hari dalam satu bulan dalam dua digit angka (00 s.d 31)
%e Hari dalam satu bulan dalam satu-dua digit angka (0 s.d 31)
Bulan
%b Nama bulan dalam tiga huruf (Jan s.d Dec)
%M Nama bulan penuh (January s.d December)
%c Bulan dalam satu-dua digit angka (0 s.d 12)
%m Bulan dalam dua digit angka (00 s.d 12)
Tahun
%Y Tahun dalam empat digit angka
%y Tahun dalam dua digit angka
Catatan: kita wajib menyertakan tanda persen (%). Tanda ini menandakan
bahwa karakter tersebut adalah karakter format tanggal.
1. SELECT DATE_FORMAT(
2. NOW(),"Tanggal: %d-%m-%Y, Pukul: %H:%i:%s"
3. ) AS Waktu
1. SELECT DATE_FORMAT(
2. NOW(),"Tanggal: %W, %e %M %Y, Pukul: %H:%i:%s"
3. ) AS Waktu
Pada contoh diatas, nama hari dan nama bulan masih dalam bahasa Inggris,
hal ini dikarenakan secara default bahasa yang digunakan adalah bahasa
Inggris, kita dapat mengubahnya dengan mendefinisikan bahasa yang
ingin digunakan. Untuk bahasa Indonesia, kita gunakan id_ID, misal:
Contoh 3: Kita juga dapat mengambil hanya data tanggal, bulan atau tahun
aja
STR_TO_DATE(string_date, format)
Pada fungsi ini, argumen format memiliki nilai seperti argumen format
pada fungsi DATE_FORMAT(), yaitu diawali dengan tanda % dan diikuti oleh
karakter tertentu (tabel 12.1). Bentuk format tanggal ini juga harus sesuai
dengan format tanggal yang ada pada argumen pertama, karena format
pada argumen kedua akan digunakan MySQL untuk memetakan mana
tanggal, bulan, tahun, dan waktu dari data yang ada di argumen pertama.
Hasil:
Pada contoh diatas, MySQL akan men-scan tanggal satu per satu mulai dari
kiri ke kanan kemudian mencocokkan dengan pola pada argumen 2.
Format yang kita gunakan pada argumen ke 2 adalah %d/%m/%Y:
%d, karena tanggal pada argumen pertama berbentuk dua digit yaitu
05
Jika kita salah dalam mengidentifikasi format tanggal, maka hasil yang
diperoleh tidak sesuai harapan, misal kita keliru menulis %Y menjadi %y:
Jika format pada argumen ke 2 tidak sesuai dengan format pada argumen
pertama (meskipun hanya satu format), maka akan menghasilkan NULL,
misal:
Hasil:
+---------+
| tanggal |
+---------+
| NULL |
+---------+
Agar dapat lebih memahami fungsi STR_TO_DATE(), mari kita coba dengan
contoh lain
Atau
Atau
1. SELECT STR_TO_DATE (
2. "Tanggal: 05-03-2017", "Tanggal: %d-%m-%Y"
3. ) AS tanggal
Contoh:
Catatan
Contoh 1:
Selanjutnya mari kita coba untuk menampilkan data buku yang terbit
hanya di tahun 2016, query yang kita jalankan:
Pada contoh diatas, pada klausa SELECT dan WHERE terdapat fungsi
komposit yaitu STR_TO_DATE() dan YEAR(). Karena format tanggal terbit
masih dd/mm/yyyy, maka untuk mendapatkan data tahun menggunakan
fungsi YEAR(), kita perlu untuk mengubah format tanggalnya menjadi
yyyy-mm-dd menggunakan fungsi STR_TO_DATE()
STR_TO_DATE(tgl_terbit, '%d/%m/%Y'), selanjutnya hasilnya akan
digunakan oleh MySQL sebagai argumen fungsi YEAR().
Contoh penggunaan:
1. SELECT judul,
2. tgl_sewa,
3. prioritas AS p,
4. CURDATE() AS tgl_sekarang,
5. DATEDIFF(
6. CURDATE(),
7. STR_TO_DATE(tgl_sewa, "%d/%m/%Y")
8. ) AS jml_hari
9. FROM persewaan_buku
Hasil:
+------------------------------------+------------+---+--------------+----------+
| judul | tgl_sewa | p | tgl_sekarang | jml_hari |
+------------------------------------+------------+---+--------------+----------+
| Pemrograman Database MySQL | 28/03/2017 | 3 | 2017-04-02 | 5 |
| PHP dan MySQL Langkah Demi Langkah | 30/03/2017 | 1 | 2017-04-02 | 3 |
| MySQL Untuk Pemula | 01/04/2017 | 2 | 2017-04-02 | 1 |
| Kumpulan Aplikasi PHP untuk Pemula | 20/03/2017 | 4 | 2017-04-02 | 13 |
+------------------------------------+------------+---+--------------+----------+
Pada contoh diatas, karena format tanggal tidak baku, kita ubah terlebih
dahulu menjadi yyyy-mm-dd dengan fungsi STR_TO_DATE()
12.5.2.Fungsi TIMEDIFF()
Fungsi TIMEDIFF() digunakan untuk menghitung perbedaan waktu.
Fungsi ini memiliki dua argumen yang wajib diisi yaitu: (1) waktu awal, (2)
waktu akhir.
Contoh penggunaan:
Hasil:
+----------------------------------+
| TIMEDIFF('07:05:30', '07:05:01') |
+----------------------------------+
| 00:00:29 |
+----------------------------------+
1. SELECT nama,
2. jam_absen,
3. MINUTE(
4. TIMEDIFF(jam_absen, "07:30:00")
5. ) AS menit_terlambat,
6. CASE
7. WHEN MINUTE(TIMEDIFF(jam_absen, "07:30:00")) < 30
8. AND MINUTE(TIMEDIFF(jam_absen, "07:30:00")) > 0
9. THEN 1
10. WHEN MINUTE(TIMEDIFF(jam_absen, "07:30:00")) >= 30
11. THEN 2
12. ELSE 0
13. END AS status_terlambat
14. FROM absen
Ketiga argumen pada fungsi ini wajib diisi. Argumen unit dapat diisi:
MICROSECOND, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, atau
YEAR. Argumen kedua dan ketiga berupa tanggal dan waktu atau tanggal
saja (minimal harus memuat tanggal), disamping itu, keduanya juga harus
memiliki format standar SQL.
Contoh:
1. SELECT TIMESTAMPDIFF(
2. MINUTE, "2017-03-01 07:30:00", "2017-03-01
3. 07:45:25"
) AS menit;
Hasil:
+-------+
| menit |
+-------+
| 15 |
+-------+
Selanjutnya kita hitung usia pendaftar, jika kurang dari 25 tahun, maka kita
beri status “umur kurang”, jika lebih, “umur cukup”. Query yang kita
jalankan:
1. SELECT nama,
2. TIMESTAMPDIFF(YEAR, tgl_lahir, CURDATE()) AS usia,
3. IF( TIMESTAMPDIFF(YEAR, tgl_lahir, CURDATE()) < 25
4. , "Umur kurang"
5. , "Umur cukup"
6. ) AS status
7. FROM pendaftaran
Hasil:
+---------+------+-------------+
| nama | usia | status |
+---------+------+-------------+
| Alfa | 26 | Umur cukup |
| Beta | 21 | Umur kurang |
| Charlie | 23 | Umur kurang |
+---------+------+-------------+
ROUND(bilangan, jumlah_desimal)
Contoh:
Hasil:
+-------------+-------------+------------------+--------------+
| ROUND(2.49) | ROUND(2.50) | ROUND(2.7159, 2) | ROUND(-2.50) |
+-------------+-------------+------------------+--------------+
| 2 | 3 | 2.72 | -3 |
+-------------+-------------+------------------+--------------+
Hasil:
+-------------+---------+------------+--------+
| nama_barang | harga | harga_jual | persen |
+-------------+---------+------------+--------+
| Televisi | 3500000 | 3250000 | 7.14% |
| AC | 3100000 | 3050000 | 1.61% |
| Kulkas | 2750000 | 2275000 | 17.27% |
+-------------+---------+------------+--------+
FLOOR(bilangan)
Contoh:
Hasil:
+------------+--------------+--------------+
| FLOOR(2.9) | FLOOR(-2.10) | FLOOR(-2.90) |
+------------+--------------+--------------+
| 2 | -3 | -3 |
+------------+--------------+--------------+
Hasil:
+-----------+-----------------+
| rata_rata | floor_rata_rata |
+-----------+-----------------+
| 74.25 | 74 |
+-----------+-----------------+
RAND(seed)
Argumen seed bersifat opsional, jika seed didefinisikan, maka nilai random
yang dihasilkan akan sama setiap kali seed digunakan, jika argumen tidak
diisi, maka setiap kali fungsi RAND() dijalankan, akan menghasilkan nilai
yang berbeda beda, contoh:
Hasil:
+---------------------+--------------------+--------------------+
| RAND() | RAND(2) | RAND(2) |
+---------------------+--------------------+--------------------+
| 0.11291463497366257 | 0.6555866465490187 | 0.6555866465490187 |
+---------------------+--------------------+--------------------+
Pada contoh diatas, fungsi RAND() yang menggunakan seed yang sama
akan menghasilkan nilai yang sama.
Seperti yang telah kita bahas diawal, bahwa fungsi RAND() ini akan selalu
menghasilkan nilai dibawah 1, untuk itu jika ingin membuat nilai random
dalam batas tertentu, kita bisa menggunakan sedikit trik.
Misal kita ingin membuat nilai random dibawah 100, maka kita tinggal
mengalikan fungsi RAND() dengan 100, misal:
Hasil:
Contoh:
Hasil:
+-----------------------------------+
| FLOOR( RAND() * (100 - 80) ) + 80 |
+-----------------------------------+
| 82 |
+-----------------------------------+
Dalam praktek, fungsi ini dapat digunakan untuk mengambil data secara
acak seperti menampilkan data artikel secara random. Untuk keperluan
tersebut, kita letakkan fungsi RAND() pada klausa ORDER BY. Misal kita
tampilkan data buku secara acak
Hasil:
Selan pada ORDER BY, fungsi RAND() juga sering digunakan pada klausa
WHERE untuk mengambil data secara acak pada range tertentu, misal:
Hasil:
+---------+------------------------------------+
| id_buku | judul |
+---------+------------------------------------+
| 4 | Kumpulan Aplikasi PHP untuk Pemula |
+---------+------------------------------------+
Pada contoh diatas, kita mengambil 1 buku dengan id_buku antara 3 s.d 5.
Output seperti ini juga dapat dihasilkan menggunakan cara lain:
1. SELECT *
2. FROM tabel_buku
3. WHERE id_buku > 2
4. ORDER BY RAND()
5. LIMIT 1
Pada query diatas, sebelum di urutkan secara acak, dengan klausa WHERE,
kita membatasi buku yang akan ditampilkan, yaitu hanya yang id_buku nya
lebih besar daripada 2.
POW(value, exponent)
Fungsi ini memiliki dua argumen yang wajib diisi, yaitu value berupa angka
numerik dan exponent merupakan angka yang digunakan sebagai pangkat,
contoh:
Hasil:
+----------+------------+
| POW(2,3) | POWER(2,3) |
+----------+------------+
| 8 | 8 |
+----------+------------+
SELECT POW(5,5);
Hasil:
+-----------+
| '1.2' + 3 |
+-----------+
| 4.2 |
+-----------+
Pada contoh diatas, MySQL akan mengubah string "1.2" menjadi float 1.2,
sehingga ketika dijumlahkan dengan 3, akan menghasilkan 4.2. Model
konversi ini disebut type casting, dan karena tidak didefinisikan dengan
jelas maka sering disebut implisit casting.
CAST(Expression AS DataType)
Fungsi diatas memiliki dua argumen yang wajib diisi, argumen tersebut
agak berbeda dengan fungsi sebelumnya karena terdapat keyword AS yang
memisahkan antara argumen satu dengan argumen kedua (biasanya antar
argumen dipisah menggunakan koma).
Contoh:
Hasil:
+---------------------------------+
| CAST('1.2' AS DECIMAL(3,1)) + 3 |
+---------------------------------+
| 4.2 |
+---------------------------------+
Salah satu contoh penggunaan fungsi CAST() ini adalah ketika kita ingin
mengurutkan kolom yang memiliki tipe data enum. Tipe data enum sering
digunakan ketika sebuah kolom hanya memiliki nilai tertentu, misal P atau
L. Misal kita memiliki tabel mahasiswa sebagai berikut:
Dengan struktur:
1. SELECT *
2. FROM mahasiswa
3. ORDER BY jenis_kelamin ASC
Hasil:
+------------+---------------+
| nama_siswa | jenis_kelamin |
+------------+---------------+
| Beta | P |
| Delta | P |
| Alfa | L |
| Charlie | L |
+------------+---------------+
1. SELECT *
2. FROM mahasiswa
3. ORDER BY CAST(jenis_kelamin AS CHAR) ASC
Pada contoh diatas, kolom jenis_kelamin kita ubah tipe datanya menjadi
CHAR, sehingga L dan P diurutkan berdasarkan urutan pada abjad dimana
L lebih kecil daripada P.
Contoh lain penggunaan CAST adalah ketika kita ingin mengurutkan data
angka, namun tipe data angka tersebut bukan numeric, melainkan
character, meskipun kondisi ini tidak ideal, tetapi dalam praktek sangat
mungkin terjadi, misal kita memiliki tabel rumah sebagai berikut:
+-------------+----------+
| jenis_rumah | no_rumah |
+-------------+----------+
| Alfa | 8 |
| Bravo | 9 |
| Charlie | 12 |
| Delta | 10 |
| Echo | 11 |
+-------------+----------+
1. SELECT *
2. FROM rumah
3. ORDER BY no_rumah
Hasil:
+-------------+----------+
| jenis_rumah | no_rumah |
+-------------+----------+
| D | 10 |
| E | 11 |
| C | 12 |
| A | 8 |
| B | 9 |
+-------------+----------+
Pada tabel diatas, karena tipe data kolom no_rumah adalah VARCHAR, maka
data pada kolom no_rumah diurutkan berdasar abjad, sehingga semua yang
berawalan 1 berada di depan. Untuk mengubah urutan sesuai angka, maka
kita perlu mengubah tipe datanya menjadi numeric (INTEGER), mari kita
ubah querynya menjadi:
1. SELECT *
2. FROM rumah
3. ORDER BY CAST(no_rumah AS UNSIGNED)
Hasil:
Seperti yang telah kita bahas, bahwa menurut jenisnya, fungsi dibagi
menjadi dua, yaitu fungsi skalar (scalar function) dan fungsi agregasi
(agregate function). Pada bab sebelumnya telah kita bahas tentang fungsi
skalar, pada bab ini kita akan membahas fungsi agregasi.
Selanjutnya mari kita hitung jumlah buku berdasarkan nomor telp nya,
jalankan query berikut:
Perlu diingat kembali bahwa NULL tidak sama dengan kosong, NULL artinya
tidak terdefinisi, sehingga pada contoh sebelumnya, string kosong pada
kolom telp (id_penerbit 4) juga ikut dihitung.
Penting juga diperhatikan bahwa NULL juga tidak sama dengan 0 (nol),
jika data mengandung nilai 0 maka akan tetap dihitung. Pada query
yang kompleks, terkadang secara tidak sengaja kita mendefinisikan
nilai 0 pada temporary table sehingga menghasilkan output yang tidak
sesuai yang diharapkan.
Khusus pada tabel dengan engine MyISAM, penggunaan asterik pada fungsi
count COUNT(*) pada statemen SELECT yang hanya melibatkan satu tabel
dan tidak ada klausa WHERE, akan diproses MySQL dengan cepat. Hal ini
dikarenakan jumlah banyaknya row sudah tersedia, sehingga MySQL
tinggal mengambilnya saja.
Contoh kita akan menjumlahkan total stok buku, query yang kita jalankan:
Contoh lain kita ingin mendapatkan total nilai seluruh buku yang ada,
untuk itu kita akan mengalikan jumlah stok dengan harga jual kemudian
keseluruhan hasilnya kita jumlahkan. Query yang kita jalankan:
Contoh kita ambil data buku dengan stok terkecil, query yang kita jalankan:
Contoh lain, kita cari data buku yang terbit paling lama, query yang kita
jalankan:
Contoh kita ambil data buku dengan stok terbanyak, query yang kita
jalankan:
Contoh lain, kita cari data buku terbaru, query yang kita jalankan:
Contoh kita hitung rata-rata harga buku, query yang kita jalankan:
1. SELECT FORMAT(AVG(harga),2)
2. FROM buku
Contoh kita tampilkan data penerbit beserta dengan (1) jumlah buku yang
diterbitkannya, (2) tanggal terakhir buku diterbitkan, (3) jumlah harga
jual, dan (4) total harga jualnya, yang dikelompokkan berdasarkan kolom
id_penerbit, query yang kita jalankan:
Pada query diatas, terdapat dua penerbit yang tidak ada data bukunya.
Seperti yang telah kita bahas pada bab sebelumnya, kita dapat melakukan
pengelompokan (GROUP BY) lebih dari satu kolom. Mari kita modifikasi
query dengan mengubah tanggal terbit buku menjadi tahun terbit buku
dan data kita kelompokkan berdasarkan kolom id_penerbit dan tahun
terbit buku. Query yang kita jalankan:
Pada contoh diatas, karena tidak ada buku yang diterbitkan oleh Studio
Press, maka nilai yang dihasilkan adalah NULL, dengan fungsi COALESCE,
MySQL akan mengambil argumen berikutnya yaitu angka 0, sehingga hasil
yang kita peroleh bukan NULL melainkan 0.
Fungsi COALESCE memiliki dua argumen atau lebih, jika argumen pertama
bernilai NULL, maka akan di diambil argumen ke dua, jika argumen kedua
juga NULL, diambil argumen ke tiga, dan seterusnya hingga menemukan
nilai selain NULL.
Pada bab ini kita akan membahas tentang ekspresi logika. Seperti pada
bahasa pemrograman umumya, ekspresi logika ini digunakan untuk
menguji suatu nilai baik nilai pada suatu kolom maupun nilai berupa
ekspresi. MySQL menyediakan dua jenis ekspresi logika yaitu ekspresi IF
dan CASE, keduanya akan kita bahas pada bab ini.
Pada MySQL, ekspresi IF dapat dibagi menjadi dua bentuk yaitu IF sebagai
fungsi dan IF sebagai statemen. Perbedaan keduanya adalah jika pada
bentuk statemen, kita dapat mengevaluasi beberapa kondisi, sedangkan
jika menggunakan fungsi, kita hanya bisa mengevaluasi satu kondisi.
14.1.1. Fungsi IF
Bentuk pertama ekspresi IF adalah fungsi. Seperti telah disinggung
sebelumnya bahwa penggunaan bentuk fungsi hanya dapat digunakan
untuk mengevaluasi satu kondisi, sehingga hanya gunakan bentuk ini jika
Jika ekspresi1 bernilai true (tidak sama dengan 0 atau tidak sama dengan
NULL) maka jalankan ekspresi2, jika tidak, jalankan ekspresi3. Contoh
sederhana:
Berikutnya, mari kita gunakan fungsi ini untuk menguji kondisi nilai suatu
tabel. Misal kita akan menampilkan data stok buku. Jika nilainya tidak sama
dengan 0, maka kita ubah output menjadi “Stok Ada” jika tidak, maka akan
menghasilkan output “Stok Kosong”. Mari kita jalankan query berikut:
Selain bentuk string, kita juga dapat mengisi nilai ekspresi dengan bentuk
lain, contoh kita ubah ekspresi2 dengan menampilkan jumlah stok, output
yang akan kita tampilkan “Stok xx buah” , jalankan query berikut:
Pada contoh diatas, ekspresi2 kita isi dengan fungsi CONCAT(). Fungsi isi
kita gunakan untuk menggabungkan string dengan nilai pada kolom stok,
Anda dapat ber-eksperimen dengan nilai lain, misal jika stok kosong
tampilkan “Stok Kosong", selain itu tampilkan jumlah stok, : IF(stok=0,
"Stok Kosong", stok)
Contoh lain, dengan operator AND kita uji apakah judul buku mengandung
kata-kata PHP dan MySQL:
Hasil:
+-----------------------------------------+------+
| judul | stok |
+-----------------------------------------+------+
| Pemrograman Database Menggunakan MySQL | 5 |
| PHP dan MySQL Langkah Demi Langkah + CD | 6 |
| MySQL Untuk Pemula | 4 |
| Kumpulan Aplikasi PHP untuk Pemula | 3 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 2 |
+-----------------------------------------+------+
14.1.2. Nested IF
Selain bentuk sederhana seperti yang kita bahas pada sub bab sebelumnya,
fungsi IF juga dapat berbentuk nested, yang artinya IF di dalam IF. Bentuk
IF ini sama seperti ketika kita membuat ternary operator pada bahasa
pemrograman PHP, ASP, atau pada Microsoft EXCEL.
IF(ekspresi1, nilai1,
IF(ekspresi2, nilai2,
IF(ekspresi3, nilai3, nilai_lain)
)
)
Penjelasan:
Jika ekspresi1 bernilai true, maka gunakan nilai1, jika tidak, maka
jalankan ekspresi2
Jika ekspresi2 bernilai true, maka gunakan nilai2, jika tidak, maka
jalankan ekspresi3
Jika ekpresi3 bernilai true, maka gunakan nilai3, jika tidak, gunakan
nilai lain
Dan seterusnya
IF (ekspresi1) {
nilai1;
} ELSE IF (ekspresi2) {
nilai2;
} ELSE IF (ekspresi3) {
ilai3;
} ELSE {
nilai_lain;
}
Contoh sederhana:
Hasil:
+------------+
| hasil |
+------------+
| Nilai lain |
+------------+
Pada contoh diatas, hasil yang kita peroleh adalah "Nilai lain", hal ini
disebabkan karena 1-1, 2-2, dan 3-3 nilainya 0 yang artinya false
Selanjutnya, mari kita tampilkan data stok buku dengan kata-kata yang
mewakili kondisi jumlah stok. Adapun kriterianya adalah sebagai berikut:
1. SELECT JUDUL,
2. IF(stok = 0, "Stok habis",
3. IF(stok > 0 AND stok < 3, "Stok tinggal sedikit",
4. IF(stok > 2 AND stok < 5, "Stok cukup", "Stok
banyak")
5. )
6. ) AS jumlah_stok
7. FROM buku;
Dengan nested IF ini, ekspresi yang dapat kita evaluasi jumlahnya tidak
terbatas, namun demikian bentuk ini akan menjadi sulit dipahami jika
ekspresi yang kita evaluasi lebih dari dua, untuk itu, ada bentuk lain yang
lebih mudah digunakan yaitu menggunakan ekspresi CASE
14.1.3. Statemen IF
Pada MySQL, ekspresi IF juga dapat berbentuk statement, bentuk ini
berupa control flow statement seperti statement IF pada bahas
pemrograman umum, seperti PHP. Dengan bentuk control flow
memudahkan kita untuk memahami alur logika yang ada. Namun
demikian, bentuk ini tidak dapat digunakan pada statemen SELECT dan
klausa yang mengikutinya, seperti klausa WHERE, melainkan hanya dapat
digunakan pada stored routines, seperti stored procedure dan stored
function.
Pada ekspresi CASE, kita mengenal dua macam istilah yaitu “Simple Case
Expression” (Ekspresi CASE Sederhana) dan “Searched CASE Expression”
(Ekspresi CASE Pencarian).
Bentuk pertama dari ekspresi CASE adalah Simple Case Expression. Pada
ekspresi ini, kita hanya menguji satu nilai. Adapun format penulisannya
adalah:
Pada query diatas, MySQL akan menguji nilai pada kolom nama_kolom. Jika
nilai pada nama_kolom = Nilai1, maka output yang dihasilkan Hasil1
jika nilai pada nama_kolom = Nilai2 maka output yang dihasilkan Hasil2
demikian seterusnya hingga tidak terbatas. Terakhir, jika semua kriteria
1. SELECT judul,
2. CASE stok
3. WHEN 0 THEN "Stok Habis"
4. END AS status_stok
5. FROM buku
Pada contoh diatas, stok yang nilainya lebih dari satu akan bernilai NULL,
hal ini karena kita tidak mendefinisikan kriteria tersebut, mari kita ubah
query diatas dengan menambahkan klausa ELSE. Jalankan query berikut:
1. SELECT judul,
2. CASE stok
3. WHEN 0 THEN "Stok Habis"
4. ELSE "Stok Tersedia"
5. END
6. FROM buku
Tidak hanya berupa string, output/hasil juga dapat kita isi dengan ekspresi
tertentu, misal kita tampilkan harga diskon pada buku tertentu
berdasarkan ID, jalankan query berikut:
Ekspresi CASE bentuk kedua adalah bentuk Searched Case Expression. Jika
sebelumnya kita menguji suatu nilai, pada bentuk ini, kita menguji
ekspresi. Adapun format penulisannya adalah:
Pada format diatas, pertama tama ekspresi1 dievaluasi, jika bernilai true,
maka dihasilkan Hasil1, jika false, maka ekspresi2 akan dievaluasi, jika
nilainya true, maka dihasilkan Hasil2, begitu seterusnya. Jika semua
kondisi tidak terpenuhi, maka akan dihasilkan nilai pada ekspresi ELSE.
Sama seperti sebelumnya, ekspresi ELSE bersifat opsional, boleh tidak
digunakan. Contoh:
1. SELECT judul,
2. CASE
3. WHEN stok = 0 THEN "Stok Habis"
4. WHEN stok > 0 AND stok < 3 THEN "Stok Sedikit"
5. WHEN stok > 2 AND stok < 5 THEN "Stok Cukup"
6. ELSE "Stok Banyak"
7. END AS status_stok
8. FROM buku
Hasil:
+-------------------------------------------------------+--------------+
| judul | status_stok |
+-------------------------------------------------------+--------------+
| Pemrograman Database Menggunakan MySQL | Stok Banyak |
| PHP dan MySQL Langkah Demi Langkah + CD | Stok Banyak |
| MySQL Untuk Pemula | Stok Cukup |
| Kumpulan Aplikasi PHP untuk Pemula | Stok Cukup |
| Pemrograman PHP Dan MySQL Untuk Pemula | Stok Sedikit |
| Blogger untuk Pemula | Stok Sedikit |
| Ide Bisnis Bermodal Blog | Stok Habis |
| ... | ... |
+-------------------------------------------------------+--------------+
Pada tabel diatas, kategori buku dibuat menjadi beberapa kolom. Sebagai
contoh, nilai X pada kolom php menandakan bahwa kategori buku tersebut
adalah php. Dengan demikian, ketika menampilkan kategori buku dalam
satu kolom, maka mustahil untuk menggunakan ekspresi CASE bentuk
simpel, karena, seperti yang telah disampaikan, bentuk simpel hanya
digunakan untuk mengevaluasi satu kolom, sebaliknya bentuk searched
dapat digunakan untuk mengevaluasi beberapa kolom.
1. SELECT judul,
2. CASE
3. WHEN php = "x" THEN "PHP"
4. WHEN mysql = "x" THEN "MySQL"
5. WHEN blog = "x" THEN "Blog"
6. END AS Kategori
7. FROM buku
Contoh:
Pada contoh diatas, dengan ekspresi CASE kita uji apakah penyebutnya
yaitu kolom harga bernilai 0, jika ya, maka hasilkan nilai 0, jika tidak maka
hitung nilai diskon.
1. SELECT *
2. FROM buku
3. ORDER BY
4. CASE
5. WHEN harga = 0
6. THEN judul
7. ELSE harga
8. END
Pada contoh diatas, jika harganya 0 maka urutkan data berdasarkan judul,
jika tidak maka urutkan data berdasarkan harganya.
Contoh lain misalkan kita memiliki tabel penjualan yang terdiri dari kolom
judul_buku, tgl_order, status order.
+------------------------------------+---------+------------+
| judul_buku | status | tgl_order |
+------------------------------------+---------+------------+
| Blogger untuk Pemula | selesai | 2017-02-17 |
| Ide Bisnis Bermodal Blog | proses | 2017-02-16 |
| Jago Wordpress | proses | 2017-02-17 |
| Kumpulan Aplikasi PHP untuk Pemula | selesai | 2017-02-15 |
| MySQL Untuk Pemula | proses | 2017-02-11 |
+------------------------------------+---------+------------+
Dalam praktek, terdapat banyak kasus yang perlu diselesaikan dengan cara
seperti diatas, intinya kita pahami terlebih alur logikanya selanjutnya
terjemahkan ke dalam query SQL.
Pada contoh diatas, data penjualan buku tanggal 2017-01-15 tidak ikut
ditampilkan. Query diatas akan mengevaluasi setiap baris data apakah
memenuhi kriteria yang ada pada klausa WHERE, jika ya, maka data
ditampilkan. Secara sederhana, klausa WHERE pada contoh diatas dapat
diibaratkan sebagai berikut:
Subquery atau sering disebut subselect atau nested query adalah query yang
berada di dalam query, lebih spesifik lagi, subquery merupakan statemen
SELECT yang berada di dalam statemen SQL lain. Hasil dari subquery ini
dapat berdiri sendiri atau digunakan oleh query utama.
SELECT *
FROM (
SELECT field1, field2
FROM tabel
WHERE field1 = 100
) AS tabel
Subquery ini sama persis seperti query pada umumnya, sehingga kita
dapat menuliskan subquery ini seperti query SQL pada umumnya (dapat
menggunakan berbagai operator, fungsi, dll). Subquery dapat diterapkan
di bagian mana saja dari SQL, disamping itu juga dapat digunakan pada
statemen SELECT, INSERT, UPDATE, dan DELETE
SELECT kolom
FROM tabel
WHERE kondisi
GROUP BY kolom
HAVING kondisi
ORDER BY kolom
Subquery dapat digunakan pada setiap bagian statemen SELECT baik pada
bagian kolom, tabel, dan kondisi. Berdasarkan posisi ini, subquery dapat
dikelompokkan menjadi tiga macam, yaitu:
Sebagai contoh, misal kita memiliki tabel uas yang berisi data nama, nilai
uas, dan tanggal sebagai berikut:
+----+--------+-------+------------+
| id | nama | nilai | tanggal |
+----+--------+-------+------------+
| 1 | Nama A | 7 | 2017-03-18 |
| 2 | Nama B | 8 | 2017-03-18 |
| 3 | Nama C | 9 | 2017-03-18 |
| 4 | Nama D | 5 | 2017-03-18 |
| 5 | Nama E | 6 | 2017-03-18 |
| 6 | Nama F | 9 | 2017-03-18 |
| 7 | Nama G | 7 | 2017-03-18 |
| 8 | Nama H | 8 | 2017-03-18 |
+----+--------+-------+------------+
Ternyata, hasilnya tidak sesuai dengan yang kita inginkan, salah satunya
karena nilai terendah untuk peringkat 5 besar adalah 7 bukan 5. Hal ini
dikarenakan pada query diatas, MySQL akan menggabungkan seluruh data
dan menjalankan fungsi agregat ( SUM, MAX, dan AVG) baru kemudian
menjalankan klausa ORDER BY dan LIMIT. Untuk itu, terlebih dahulu harus
kita urutkan data menggunakan subquery, sehingga querynya menjadi
berikut:
Penjelasan:
1. SELECT nilai
2. FROM `uas`
3. ORDER BY nilai DESC
4. LIMIT 5
Terdapat tabel lain yang bernama penjualan yang terdiri dari field
id_transaksi, id_barang, tgl_transaksi, dan harga dimana field
id_barang pada tabel ini merupakan foreign key dari field id_barang
1. SELECT id_barang,
2. nama_barang,
3. penjualan.harga,
4. COUNT(id_transaksi) AS jumlah,
5. penjualan.harga * COUNT(id_transaksi) AS total,
6. MAX(tanggal) AS transaksi_terakhir
7. FROM barang
8. LEFT JOIN penjualan AS penjualan USING(id_barang)
9. WHERE MONTH(tanggal) = 3
10. GROUP BY id_barang
1. SELECT id_barang,
2. nama_barang,
3. penjualan.harga,
4. IFNULL(jumlah, 0) AS jumlah,
5. IFNULL(penjualan.harga * jumlah, 0) AS total,
6. IFNULL(tanggal, "-") AS "Transaksi Terakhir"
7. FROM barang
8. LEFT JOIN
9. (
10. SELECT id_barang, harga,
11. COUNT(id_barang) AS jumlah,
12. MAX(tanggal) AS tanggal
13. FROM penjualan
14. WHERE YEAR(tanggal) = 2017
15. AND MONTH(tanggal) = 3
16. GROUP BY id_barang
17. ) AS penjualan
Penjelasan:
Query diatas terdiri dari dua bagian, yaitu query utama dan subquery.
Adapun subquerynya adalah sebagai berikut:
1. SELECT id_barang,
2. nama_barang,
3. penjualan.harga,
4. IFNULL(jumlah, 0) AS jumlah,
5. IFNULL(penjualan.harga * jumlah, 0) AS total,
6. IFNULL(tanggal, "-") AS "Transaksi Terakhir"
7. FROM tabel_barang
8. LEFT JOIN (subquery) AS penjualan
9. USING (id_barang)
10. GROUP BY id_barang
Seperti telah kita bahas pada bab sebelumnya, kita harus mendefinisikan
nama tabel jika ada nama kolom yang sama. Pada contoh diatas, kita harus
mendefinisikan nama tabel pada kolom harga karena nama kolom
tersebut ada di tabel tabel_barang dan tabel_penjualan, dengan
demikian MySQL tahu bahwa kita akan menggunakan kolom harga pada
tabel penjualan (hasil dari subquery)
1. SELECT id_barang,
2. nama_barang,
3. IFNULL(penjualan.harga, 0) AS harga_trx,
4. IFNULL(jumlah, 0) AS jumlah,
5. IFNULL(penjualan.harga * jumlah, 0) AS total,
Hasil yang kita peroleh telah sesuai dengan yang kita harapkan, namun,
pertimbangkan penggunaan query berikut:
1. SELECT id_barang,
2. nama_barang,
3. IFNULL(penjualan.harga, 0) AS harga_trx,
4. IFNULL(COUNT(id_transaksi), 0) AS jumlah,
5. IFNULL(penjualan.harga * COUNT(id_transaksi), 0)
AS total,
6. IFNULL(tanggal, "-") AS trx_trakhir
7. FROM barang
8. LEFT JOIN penjualan USING (id_barang)
9. GROUP BY id_barang
mysql> SELECT *
-> FROM barang
-> LEFT JOIN penjualan USING (id_barang);
+-----------+-------------+---------+--------------+------------+---------+
| id_barang | nama_barang | harga | id_transaksi | tanggal | harga |
+-----------+-------------+---------+--------------+------------+---------+
| 1 | RAM | 230000 | 2 | 2017-03-12 | 230000 |
| 2 | Mainboard | 1250000 | 3 | 2017-03-15 | 1250000 |
| 2 | Mainboard | 1250000 | 4 | 2017-02-17 | 1250000 |
| 3 | Pocessor | 1150000 | 5 | 2017-03-13 | 1150000 |
| 3 | Pocessor | 1150000 | 6 | 2017-02-16 | 1150000 |
| 2 | Mainboard | 1250000 | 7 | 2017-03-12 | 1250000 |
| 2 | Mainboard | 1250000 | 8 | 2017-02-19 | 1250000 |
| 3 | Pocessor | 1150000 | 9 | 2017-03-11 | 1150000 |
| 1 | RAM | 230000 | 10 | 2017-02-09 | 230000 |
| 4 | Mouse | 85000 | NULL | NULL | NULL |
| 5 | Keyboard | 80000 | NULL | NULL | NULL |
+-----------+-------------+---------+--------------+------------+---------+
11 rows in set (0.00 sec)
Seperti sifat operator yang telah kita bahas pada bab sebelumnya, bahwa
ketika membandingkan suatu nilai menggunakan operator pembanding,
maka MySQL akan menyesuaikan tipe data kedua nilai tersebut. Pada
contoh ini kebetulan hasil subquery berupa numeric sehingga dapat
langsung dibandingkan dengan kolom harga, jika hasilnya bukan numeric,
misal string, hasil yang kita peroleh juga sama.
1. SELECT id_barang,
2. nama_barang,
3. tanggal,
4. penjualan.harga
5. FROM penjualan
6. LEFT JOIN barang USING (id_barang)
7. WHERE id_barang = 2 AND
8. penjualan.harga < ( SELECT harga
9. FROM barang
10. WHERE id_barang = 2
11. )
Pada tabel barang kita ketahui bahwa id_barang dari Mainboard adalah 2,
sehingga pada query diatas, kita menyeleksi barang berdasarkan id_barang
yaitu 2. Pada klausa WHERE, subquery akan menghasilkan list price dari
Pada operator yang mensyaratkan satu nilai, jika row yang dihasilkan lebih
dari satu maka akan menghasilkan pesan error, misal:
Demikian juga jika kolom yang dihasilkan lebih dari satu, misal:
Pada bab 9, kita sudah belajar mengenai operator IN, contoh penggunaan
operator ini adalah:
Pada contoh diatas, nilai pada operator IN bersifat dinamis, sesuai dengan
banyaknya data transaksi.
1. SELECT id_barang,
2. nama_barang
3. FROM penjualan
4. LEFT JOIN barang USING (id_barang)
5. WHERE id_transaksi IN ( SELECT id_transaksi
6. FROM penjualan
7. GROUP BY id_barang
8. HAVING count(*) > 2
9. )
1. SELECT id_barang,
2. nama_barang
3. FROM penjualan
4. LEFT JOIN barang USING (id_barang)
5. WHERE id_transaksi IN (3,5)
1. SELECT id_barang,
2. nama_barang
3. FROM penjualan
4. LEFT JOIN barang USING (id_barang)
5. WHERE id_transaksi = ANY (SELECT id_transaksi
6. FROM penjualan
7. GROUP BY id_barang
8. HAVING count(*) > 2
9. )
Perhatikan bahwa pada cara kedua ini kita menggunakan JOIN untuk
menggabungkan tabel penjualan dan tabel barang
Sebagai contoh kita tampilkan data barang yang penjualannya diatas Rp.
1.000.000. Query yang kita jalankan:
1. SELECT SUM(harga)
2. FROM penjualan
3. WHERE penjualan.id_barang = barang.id_barang
Untuk dapat memahami query diatas, kita lihat bentuk query secara global
sebagai berikut:
1. SELECT id_barang,
2. nama_barang
3. FROM barang AS tb
4. WHERE EXISTS( SELECT *
5. FROM penjualan AS tp
6. WHERE tb.id_barang = tp.id_barang
7. )
Pada query diatas, subquery tidak berdiri sendiri karena klausa WHERE
menggunakan tabel yang ada pada query utama. Klausa EXISTS akan
mengecek subquery apakah menghasilkan data, jika ya maka bernilai true
dan data nama_barang ditampilkan.
Sama seperti sebelumnya, kita juga dapat menghasilkan output yang sama
tanpa menggunakan subquery:
1. SELECT id_barang,
2. nama_barang
3. FROM penjualan
4. JOIN barang USING(id_barang)
5. GROUP BY id_barang
1. SELECT id_barang,
2. nama_barang
3. FROM barang AS tb
4. WHERE id_barang IN ( SELECT id_barang FROM penjualan )
1. SELECT nama_barang,
2. (SELECT COUNT(id_transaksi)
3. FROM penjualan
4. WHERE barang.id_barang = penjualan.id_barang
5. ) AS jml_transaksi
6. FROM barang
7. ORDER BY id_barang
Seperti pada tabel hasil query, subquery menghasilkan satu nilai yang akan
diletakkan di kolom jml_transaksi
Seperti biasa, kita juga dapat menghasilkan output yang sama tanpa
subquery, query penggantinya adalah:
1. SELECT id_barang,
2. nama_barang,
3. COUNT(id_transaksi) AS jml_transaksi
4. FROM barang
5. LEFT JOIN penjualan USING (id_barang)
6. GROUP BY barang.id_barang
Pada query diatas kita menggunakan outer join ( LEFT JOIN ) untuk
menampilkan semua data nama_barang yang ada pada tabel barang. Hasil
penggabungan tersebut seperti tampak pada tabel berikut:
mysql> SELECT * FROM barang LEFT JOIN penjualan USING (id_barang);
+-----------+-------------+---------+--------------+------------+---------+
| id_barang | nama_barang | harga | id_transaksi | tanggal | harga |
+-----------+-------------+---------+--------------+------------+---------+
| 1 | RAM | 230000 | 2 | 2017-03-12 | 230000 |
| 2 | Mainboard | 1250000 | 3 | 2017-03-15 | 1150000 |
| 2 | Mainboard | 1250000 | 4 | 2017-02-17 | 1250000 |
| 3 | Pocessor | 1150000 | 5 | 2017-03-13 | 1150000 |
| 3 | Pocessor | 1150000 | 6 | 2017-02-16 | 1150000 |
| 2 | Mainboard | 1250000 | 7 | 2017-03-12 | 1050000 |
| 2 | Mainboard | 1250000 | 8 | 2017-02-19 | 1250000 |
| 3 | Pocessor | 1150000 | 9 | 2017-03-11 | 1150000 |
| 1 | RAM | 230000 | 10 | 2017-02-09 | 230000 |
| 4 | Mouse | 85000 | NULL | NULL | NULL |
| 5 | Keyboard | 80000 | NULL | NULL | NULL |
+-----------+-------------+---------+--------------+------------+---------+
11 rows in set (0.00 sec)
1. SELECT id_barang,
2. nama_barang,
3. COUNT(id_transaksi) AS jml_transaksi,
4. SUM(penjualan.harga) AS jml_penjualan,
5. (SELECT SUM(harga) FROM penjualan) AS total,
6. CONCAT(
7. ROUND(
8. SUM(penjualan.harga)
9. / (SELECT SUM(harga) FROM penjualan)
10. * 100
11. , 2
12. )
13. , "%"
14. ) AS persen
15. FROM barang
16. LEFT JOIN penjualan USING (id_barang)
17. GROUP BY barang.id_barang
Dari berbagai contoh kasus yang disajikan pada bab ini, banyak
diantaranya yang menunjukkan bahwa subquery dapat digantikan dengan
JOIN, sehingga, jika Anda mendapati performa subquery menurun, Anda
dapat mempertimbangkan menggantinya dengan JOIN.
Pada bab sebelumnya, kita telah membahas tentang join dan subquery.
Pada sebagian orang, subquery ini rancu dengan union. Meskipun sama
sama dapat menambahkan data, pada join dan subquery, penambahan
terjadi pada jumlah kolom (penggabungan secara horizontal), sedangkan
pada UNION, penambahan tersebut terjadi pada baris (penggabungan
secara vertikal). Perbedaan keduanya seperti tampak seperti gambar
berikut ini.
Pada gambar diatas, terlihat bahwa pada UNION, kita menggabungkan tabel
dengan menempatkan tabel kedua dibawah tabel pertama (tabel yang
dimaksud disini adalah tabel yang dihasilkan oleh query SELECT)
Pada MySQL, terdapat dua macam operator union yaitu UNION dan UNION
ALL. UNION digunakan untuk menggabungkan tabel dimana baris yang
memiliki data yang sama di semua kolomnya, akan digabungkan menjadi
satu, sedangkan UNION ALL akan menggabungkan tabel apa adanya tanpa
menggabungkan baris yang datanya sama.
Pada tabel diatas terlihat bahwa setelah tabel digabungkan, maka baris
yang datanya sama (baris dengan id 2) akan digabungkan. Selanjutnya, jika
kita menggunakan UNION ALL, maka, hasil yang kita peroleh:
+-----------+------------+-----------+
| id_retur | tgl_retur | jml_retur |
+-----------+------------+-----------+
| 1 | 2017-03-10 | 3500000 |
| 1 | 2017-03-12 | 3250000 |
| 2 | 2017-02-15 | 3100000 |
| 2 | 2017-02-15 | 3100000 |
Dari tabel diatas terlihat bahwa MySQL akan menggabungkan Tabel A dan
Tabel B apa adanya dan baris yang datanya sama (baris dengan id 2) tidak
digabung.
Pada contoh diatas, terlihat bahwa UNION terdiri dari beberapa statemen
SELECT. Untuk lebih mudah memahami penulisan statemen SELECT pada
UNION, mari kita lihat lagi format penulisan statemen SELECT yang telah
kita bahas pada BAB 8
SELECT nama_kolom
FROM nama_tabel
WHERE kondisi
GROUP BY nama_kolom
ORDER BY nama_kolom
HAVING kriteria
LIMIT jumlah
Ketika menggunakan UNION dan UNION ALL, terdapat beberapa hal penting
yang perlu diperhatikan:
1. Pada setiap klausa SELECT, jumlah kolom kedua tabel harus sama,
namun demikian, tipe data dari kolom yang akan digabungkan tidak
harus sama, MySQL akan mengubahnya sesuai keperluan. Misal pada
tabel pertama, tipe data pada kolom pertama berupa angka (INT)
sedangkan pada tabel kedua, tipe data pada kolom pertama berupa
character (CHAR)
2. Jika panjang data dari kolom masing masing tabel berbeda, maka
ketika tabel digabungkan, MySQL akan menggunakan panjang data
yang terpanjang, misal kolom ketiga pada tabel pertama menggunakan
tipe data CHAR(5) sedangkan kolom ketiga pada tabel kedua
menggunakan CHAR(10), maka ketika tabel digabungkan, tipe data
yang digunakan adalah CHAR(10)
3. Nama kolom yang digunakan pada tabel hasil UNION adalah nama
kolom pada statemen SELECT yang pertama.
Agar lebih paham tentang UNION dan UNION ALL mari kita bahas beberapa
contoh kasus.
Contoh 1: Misal kita memiliki dua buah tabel dengan nama penjualan dan
retur. Adapun isi dari kedua tabel adalah sebagai berikut:
Tabel penjualan
Tabel retur
+----------+--------+--------------+------------+-------------+
| id_retur | id_trx | id_pelanggan | tgl_retur | nilai_retur |
+----------+--------+--------------+------------+-------------+
| 1 | 2 | 2 | 2017-03-29 | 175000 |
| 2 | 7 | 4 | 2017-03-21 | 215000 |
+----------+--------+--------------+------------+-------------+
Perhatikan bahwa pada tabel yang dihasilkan, nama kolom yang digunakan
adalah nama kolom pada tabel pertama. Disamping itu, kita juga
menambahkan satu kolom yaitu jenis_trx yang berisi "order" untuk tabel
pertama dan "retur" untuk tabel kedua. Hal ini untuk membedakan mana
baris yang berasal dari tabel penjualan dan mana yang dari tabel retur.
Tips: Jika kita menggunakan klausa ORDER BY, gunakan selalu nama
kolom yang ada pada statemen SELECT yang pertama.
16.2. Precedence
Ketika kita menggabungkan banyak tabel menggunakan UNION dan UNION
ALL, maka kita perlu memperhatikan urutan dari masing masing statemen
SELECT. Misal kita gabungkan tabel pelanggan, tabel penjualan, dan tabel
retur dengan query sebagai berikut:
Hasil tersebut berbeda dengan yang pertama karena pada query yang
kedua ini, pertama tama tabel pelanggan akan digabungkan dengan tabel
transaksi menggunakan UNION ALL baru kemudian hasilnya digabung
menggunakan UNION. Karena yang terakhir digunakan adalah UNION maka
semua baris yang sama akan dihilangkan.
Tips: Dari contoh diatas, dapat kita simpulkan bahwa jika kita ingin
menggunakan UNION dan UNION ALL dalam satu query maka selalu
tempatkan UNION ALL setelah UNION
1. SELECT *
2. FROM (
3. SELECT id_pelanggan, tgl_trx AS tanggal, "order"
AS jenis_trx
4. FROM penjualan
5. ORDER BY tgl_trx DESC
6. LIMIT 5
7. ) AS transaksi
8. UNION ALL
9. SELECT id_pelanggan, tgl_retur, "retur" AS jenis_trx
10. FROM retur
Jika kita tetap menggunakan klausa ORDER BY pada statemen SELECT tanpa
menggunakan subquery, maka kita akan mendapatkan pesan error sebagai
berikut:
Cara lain yang dapat digunakan untuk menghasilkan output yang sama
yaitu dengan memberikan tanda kurung pada statemen SELECT. Seperti
telah kita bahas pada bab sebelumnya, bahwa ekspresi yang berada di
dalam tanda kurung akan didahulukan oleh MySQL. Contoh kita ubah
query menjadi seperti ini:
Karena berada di dalam tanda kurung, maka statemen kedua ini akan
dieksekusi terlebih dahulu sehingga menghasilkan tabel dengan jumlah
baris 2, selanjutnya tabel tersebut digabungkan dengan tabel pertama.
Pada query diatas, terlebih dahulu kita gabungkan tabel penjualan dengan
tabel retur menggunakan UNION ALL baru kemudian hasilnya digabungkan
dengan tabel pelanggan.
Selanjutnya, kita akan menampilkan data tabel tersebut beserta total nilai
transaksinya, query yang kita jalankan:
Hasil:
Perhatikan bahwa terdapat tambahan baris pada baris paling bawah. Baris
tersebut adalah hasil dari klausa WITH ROLLUP. Beberapa hal yang perlu
diperhatikan terkait baris baru tersebut:
2. Kolom selain yang ada pada klausa GROUP BY dan kolom yang dihitung
nilai totalnya (nilai_trx), yang pada contoh ini adalah kolom nama,
bln_trx, thn_trx akan otomatis diisi oleh MySQL dengan nilai
tertentu yang umumnya nilai pada baris sebelumnya,
Hasil:
+--------+---------+---------+---------+-----------+
| id_trx | nama | bln_trx | thn_trx | nilai_trx |
+--------+---------+---------+---------+-----------+
| 1 | Alfa | 3 | 2017 | 250000 |
| 2 | Charlie | 12 | 2016 | 175000 |
| 3 | Bravo | 3 | 2017 | 310000 |
| 4 | Bravo | 11 | 2016 | 250000 |
| 5 | Alfa | 3 | 2017 | 300000 |
| 6 | Charlie | 11 | 2016 | 350000 |
| 7 | Bravo | 3 | 2017 | 275000 |
| 8 | Bravo | 12 | 2016 | 150000 |
| NULL | Bravo | 12 | 2016 | 150000 |
+--------+---------+---------+---------+-----------+
Dari penjelasan diatas, kita sudah mulai paham bagaimana membuat baris
total dengan klausa WITH ROLLUP, lebih lanjut, mari kita bahas cara
membuat baris subtotal, kali ini kita buat total berdasarkan nama dan
bulan transaksi, jalankan query berikut:
Hasil:
+---------+---------+---------------+----------------+
| bln_trx | nama | COUNT(id_trx) | SUM(nilai_trx) |
+---------+---------+---------------+----------------+
| 3 | Alfa | 2 | 550000 |
| 3 | Bravo | 2 | 585000 |
| 3 | NULL | 4 | 1135000 |
| 11 | Bravo | 1 | 250000 |
| 11 | Charlie | 1 | 350000 |
Keterangan gambar:
Hasil:
+---------+---------+---------+---------------+----------------+
| thn_trx | bln_trx | nama | COUNT(id_trx) | SUM(nilai_trx) |
+---------+---------+---------+---------------+----------------+
| 2016 | 11 | Bravo | 1 | 250000 |
| 2016 | 11 | Charlie | 1 | 350000 |
| 2016 | 11 | NULL | 2 | 600000 |
| 2016 | 12 | Bravo | 1 | 150000 |
| 2016 | 12 | Charlie | 1 | 175000 |
| 2016 | 12 | NULL | 2 | 325000 |
| 2016 | NULL | NULL | 4 | 925000 |
| 2017 | 3 | Alfa | 2 | 550000 |
| 2017 | 3 | Bravo | 2 | 585000 |
| 2017 | 3 | NULL | 4 | 1135000 |
| 2017 | NULL | NULL | 4 | 1135000 |
| NULL | NULL | NULL | 8 | 2060000 |
+---------+---------+---------+---------------+----------------+
Keterangan gambar:
Dengan memperhatikan hasil pada dua contoh terakhir, dapat kita ketahui
bahwa MySQL memberi nilai NULL pada setiap kolom hasil WITH ROLLUP.
Agar hasil query lebih mudah dibaca, mari kita ganti nilai NULL menjadi
nilai lain, misal TOTAL, kita ubah query menjadi berikut:
1. SELECT
2. IFNULL(thn_trx, "TOTAL") AS tahun,
3. IFNULL(bln_trx, "TOTAL") AS bulan,
4. IFNULL(nama, "TOTAL") AS nama_sales,
5. COUNT(id_trx),
6. SUM(nilai_trx)
7. FROM sales
8. GROUP BY thn_trx, bln_trx, nama
9. WITH ROLLUP
Pada contoh diatas, kita gunakan fungsi IFNULL() untuk mengubah nilai
NULL menjadi kata Total.
Hasil:
+------------+---------------+----------------+
| nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+------------+---------------+----------------+
| Alfa | 2 | 550000 |
| Bravo | 2 | 560000 |
| Charlie | 1 | 175000 |
| NULL | 5 | 1285000 |
+------------+---------------+----------------+
Pada contoh diatas, terlihat bahwa pada kolom nama_sales, nilai NULL tidak
berubah menjadi TOTAL karena pada klausa GROUP BY, kita menggunakan
nama kolom alias yaitu nama_sales, untuk memperbaikinya, gunakan nama
kolom sehingga klausa GROUP BY menjadi GROUP BY nama
1. SELECT
2. IFNULL(MONTH(tgl_trx), "TOTAL") as bln_trx,
3. IFNULL(nama, "TOTAL") as nama_sales,
4. COUNT(id_trx),
5. SUM(nilai_trx)
6. FROM sales2
7. GROUP BY MONTH(tgl_trx), nama
8. WITH ROLLUP
Hasil:
+---------+------------+---------------+----------------+
| bln_trx | nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+---------+------------+---------------+----------------+
| 2 | Bravo | 2 | 560000 |
Pada contoh diatas, terlihat bahwa nilai baris terakhir kolom bln_trx
adalah 3, sejauh yang kita pelajari, baris ini seharusnya berisi string TOTAL,
kenapa bisa seperti itu? hal ini disebabkan karena data dikelompokkan
berdasarkan nilai output dari suatu fungsi, yang dalam hal ini fungsi
YEAR()
Contoh lain: kita kelompokkan data berdasarkan nama sales yang diubah
hurufnya menjadi huruf kapital semua:
1. SELECT
2. IFNULL(UPPER(nama), "TOTAL") as nama_sales,
3. COUNT(id_trx),
4. SUM(nilai_trx)
5. FROM sales2
6. GROUP BY UPPER(nama)
7. WITH ROLLUP
Hasil:
+------------+---------------+----------------+
| nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+------------+---------------+----------------+
| ALFA | 2 | 550000 |
| BRAVO | 2 | 560000 |
| CHARLIE | 1 | 175000 |
| CHARLIE | 5 | 1285000 |
+------------+---------------+----------------+
Untuk mengatasi berbagai permasalahan diatas, salah satu cara yang dapat
kita gunakan adalah menggunakan subquery, contoh:
Hasil:
+---------+------------+---------+-----------+
| bln_trx | nama_sales | jml_trx | total_trx |
+---------+------------+---------+-----------+
| 2 | Bravo | 2 | 560000 |
| 2 | TOTAL | 2 | 560000 |
| 3 | Alfa | 2 | 550000 |
| 3 | Charlie | 1 | 175000 |
| 3 | TOTAL | 3 | 725000 |
| TOTAL | TOTAL | 5 | 1285000 |
+---------+------------+---------+-----------+
Pada implisit order, kita dapat mengubah bentuk urutan dengan cara
menambahkan ASC atau DESC pada klausa GROUP BY, misal kita ingin
Hasil:
+-------+-------+------------+---------------+----------------+
| tahun | bulan | nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+-------+-------+------------+---------------+----------------+
| 2017 | 3 | Alfa | 2 | 550000 |
| 2017 | 3 | Bravo | 2 | 585000 |
| 2017 | 3 | TOTAL | 4 | 1135000 |
| 2017 | TOTAL | TOTAL | 4 | 1135000 |
| 2016 | 12 | Bravo | 1 | 150000 |
| 2016 | 12 | Charlie | 1 | 175000 |
| 2016 | 12 | TOTAL | 2 | 325000 |
| 2016 | 11 | Bravo | 1 | 250000 |
| 2016 | 11 | Charlie | 1 | 350000 |
| 2016 | 11 | TOTAL | 2 | 600000 |
| 2016 | TOTAL | TOTAL | 4 | 925000 |
| TOTAL | TOTAL | TOTAL | 8 | 2060000 |
+-------+-------+------------+---------------+----------------+
Query diatas dapat berjalan dengan baik sesuai dengan yang diharapkan,
namun sayangnya, pada MySQL versi 5.7, fitur ini sudah deprecated yang
artinya sudah tidak disarankan lagi untuk digunakan karena pada versi
berikutnya, fitur ini akan dihilangkan. Untuk itu disarankan untuk
menggunakan eksplisit order dengan menggunakan klausa ORDER BY.
Dengan eksplisit order, query diatas dapat kita ubah menjadi:
1. SELECT * FROM
2. (
3. SELECT IFNULL(thn_trx, 'TOTAL') AS tahun,
4. IFNULL(bln_trx, 'TOTAL') AS bulan,
5. IFNULL(nama, 'TOTAL') AS nama_sales,
Hasil:
+-------+-------+------------+---------------+----------------+
| tahun | bulan | nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+-------+-------+------------+---------------+----------------+
| TOTAL | TOTAL | TOTAL | 8 | 2060000 |
| 2017 | TOTAL | TOTAL | 4 | 1135000 |
| 2017 | 3 | Alfa | 2 | 550000 |
| 2017 | 3 | Bravo | 2 | 585000 |
| 2017 | 3 | TOTAL | 4 | 1135000 |
| 2016 | TOTAL | TOTAL | 4 | 925000 |
| 2016 | 12 | Bravo | 1 | 150000 |
| 2016 | 12 | Charlie | 1 | 175000 |
| 2016 | 12 | TOTAL | 2 | 325000 |
| 2016 | 11 | Bravo | 1 | 250000 |
| 2016 | 11 | Charlie | 1 | 350000 |
| 2016 | 11 | TOTAL | 2 | 600000 |
+-------+-------+------------+---------------+----------------+
Penjelasan:
Bagaimana mengatasi hal tersebut? Sampai saat ini, tidak ada cara yang
elegan untuk mengatasinya, kita hanya bisa mengakalinya dengan
memberi nama pada baris TOTAL sedemikian rupa sehingga jika diurutkan,
posisinya akan berada dibawah, misal kita ubah query menjadi berikut ini:
Hasil:
+---------+---------+------------+---------------+----------------+
| tahun | bulan | nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+---------+---------+------------+---------------+----------------+
| 2017 | 3 | Alfa | 2 | 550000 |
| 2017 | 3 | Bravo | 2 | 585000 |
| 2017 | 3 | TOTAL | 4 | 1135000 |
| 2017 | 1-TOTAL | TOTAL | 4 | 1135000 |
| 2016 | 12 | Bravo | 1 | 150000 |
| 2016 | 12 | Charlie | 1 | 175000 |
| 2016 | 12 | TOTAL | 2 | 325000 |
| 2016 | 11 | Bravo | 1 | 250000 |
| 2016 | 11 | Charlie | 1 | 350000 |
| 2016 | 11 | TOTAL | 2 | 600000 |
| 2016 | 1-TOTAL | TOTAL | 4 | 925000 |
| 1-TOTAL | 1-TOTAL | TOTAL | 8 | 2060000 |
+---------+---------+------------+---------------+----------------+
Pada contoh diatas, kita tambahkan awalan 1- pada TOTAL yang ada di
kolom tahun dan bulan, karena jika diurutkan menurun, angka satu akan
berada di paling bawah. Model penamaan ini sangat tergantung dengan
jenis data yang ditampilkan.
Hasil:
+-------+-------+------------+---------------+----------------+
| tahun | bulan | nama_sales | COUNT(id_trx) | SUM(nilai_trx) |
+-------+-------+------------+---------------+----------------+
| 2016 | 11 | Bravo | 1 | 250000 |
| 2016 | 11 | Charlie | 1 | 350000 |
| 2016 | 11 | TOTAL | 2 | 600000 |
| 2016 | 12 | Bravo | 1 | 150000 |
| 2016 | 12 | Charlie | 1 | 175000 |
+-------+-------+------------+---------------+----------------+
Seperti telah kita ketahui, data pada database disimpan dalam bentuk
tabel. Untuk menyajikan data tersebut, terkadang kita perlu mengolahnya
terlebih dahulu sehingga bentuk data yang disajikan menjadi lebih
informatif. Pada BAB ini, kita akan membahas salah satu bentuk penyajian
data yang sering digunakan yaitu bentuk pivot table atau cross tab, bentuk
ini sering kita jumpai pada Microsoft Excel.
Secara sederhana, pivot table adalah proses mengubah data dari baris
menjadi kolom, jika diperlukan, proses ini juga akan melakukan berbagai
rekapitulasi data. Bentuk pivot table lebih informatif dibanding bentuk
konvensional terutama ketika digunakan untuk membandingkan data
secara horizontal.
Hasil:
+------------+---------+----------+---------+
| NAMA_SALES | januari | februari | total |
+------------+---------+----------+---------+
| Alfa | 375000 | 815000 | 1190000 |
| Bravo | 310000 | 525000 | 835000 |
| Charlie | 525000 | 300000 | 825000 |
| Delta | 0 | 1000000 | 1000000 |
| TOTAL | 1210000 | 2640000 | 3850000 |
+------------+---------+----------+---------+
SUM(nilai_trx) AS januari
Hasil:
+------------+-------+---------+-------+---------+---------+---------+
| nama_sales | trx_1 | bln_1 | trx_2 | bln_2 | jml_trx | total |
+------------+-------+---------+-------+---------+---------+---------+
| Alfa | 2 | 375000 | 3 | 815000 | 5 | 1190000 |
| Bravo | 1 | 310000 | 2 | 525000 | 3 | 835000 |
| Charlie | 2 | 525000 | 1 | 300000 | 3 | 825000 |
| Delta | 0 | 0 | 2 | 1000000 | 2 | 1000000 |
| TOTAL | 5 | 1210000 | 8 | 2640000 | 13 | 3850000 |
+------------+-------+---------+-------+---------+---------+---------+
Hasil:
+------------+-----------+------+---------+------+---------+--------+---------+
| nama_sales | sales_tim | tx_1 | bln_1 | tx_2 | bln_2 | jml_tx | total |
+------------+-----------+------+---------+------+---------+--------+---------+
| Alfa | 1 | 2 | 375000 | 3 | 815000 | 5 | 1190000 |
| Bravo | 1 | 1 | 310000 | 2 | 525000 | 3 | 835000 |
| SUB TOTAL | 1 | 3 | 685000 | 5 | 1340000 | 8 | 2025000 |
| Charlie | 2 | 2 | 525000 | 1 | 300000 | 3 | 825000 |
| Delta | 2 | 0 | 0 | 2 | 1000000 | 2 | 1000000 |
| SUB TOTAL | 2 | 2 | 525000 | 3 | 1300000 | 5 | 1825000 |
| SUB TOTAL | TOTAL | 5 | 1210000 | 8 | 2640000 | 13 | 3850000 |
+------------+-----------+------+---------+------+---------+--------+---------+
Perhatikan bahwa sekarang muncul baris baru dengan nilai SUB TOTAL,
baris ini muncul karena kita menambahkan kolom tim pada klausa GROUP
BY, sehingga ketika klausa WITH ROLLUP dijalankan, MySQL akan
menghitung subtotal berdasarkan nilai yang sama yang ada pada kolom
tim.
Kenapa bisa demikian? Seperti yang telah kita bahas pada bab 17, ketika
menjalankan klausa GROUP BY, MySQL akan sekaligus mengurutkan data
berdasarkan kolom yang ada pada klausa tersebut secara ascending (urut
dari terkecil ke terbesar), model ini sering disebut implisit order. Kita
dapat mengubah pola pengurutan ini dengan menambahkan ASC atau DESC
pada klausa GROUP BY, misal kita ubah urutan data pada kolom
nama_sales dan sales_tim menjadi descending.
Seperti yang telah kita bahas pada bab 17, cara ini merupakan cara yang
paling mudah untuk mengubah urutan data pada klausa GROUP BY, namun,
pada MySQL versi 5.7, fitur ini sudah deprecated, artinya tidak disarankan
untuk digunakan, karena ke depan fitur ini akan dihapus, untuk itu,
disarankan untuk menggunakan eksplisit order dengan menggunakan
klausa ORDER BY. Selanjutnya mari kita jalankan query berikut:
1. SELECT * FROM (
2. SELECT IFNULL(nama, '1 - SUB TOTAL') AS nama_sales,
3. IFNULL(tim, '0 - TOTAL') as sales_tim,
4. COUNT(IF(MONTH(tgl_trx) = 1, nilai_trx, NULL)) AS trx_1,
5. SUM(IF(MONTH(tgl_trx) = 1, nilai_trx, 0)) AS bln_1,
6. COUNT(IF(MONTH(tgl_trx) = 2, nilai_trx, NULL)) AS trx_2,
7. SUM(IF(MONTH(tgl_trx) = 2, nilai_trx, 0)) AS bln_2,
8. COUNT(nilai_trx) AS jml_trx,
9. SUM(nilai_trx) AS total
10. FROM sales3
11. GROUP BY tim, nama
12. WITH ROLLUP
13. ) AS sales
14. ORDER BY sales_tim DESC, nama_sales DESC
Hasil:
+---------------+-----------+-------+---------+-------+---------+---------+---------+
| nama_sales | sales_tim | trx_1 | bln_1 | trx_2 | bln_2 | jml_trx | total |
+---------------+-----------+-------+---------+-------+---------+---------+---------+
| Delta | 2 | 0 | 0 | 2 | 1000000 | 2 | 1000000 |
| Charlie | 2 | 2 | 525000 | 1 | 300000 | 3 | 825000 |
| 1 - SUB TOTAL | 2 | 2 | 525000 | 3 | 1300000 | 5 | 1825000 |
| Bravo | 1 | 1 | 310000 | 2 | 525000 | 3 | 835000 |
| Alfa | 1 | 2 | 375000 | 3 | 815000 | 5 | 1190000 |
| 1 - SUB TOTAL | 1 | 3 | 685000 | 5 | 1340000 | 8 | 2025000 |
| 1 - SUB TOTAL | 0 - TOTAL | 5 | 1210000 | 8 | 2640000 | 13 | 3850000 |
+---------------+-----------+-------+---------+-------+---------+---------+---------+
Jika kita menggunakan klausa WITH ROLLUP, maka baris total akan selalu
berada diatas karena pasti jumlahnya paling besar, untuk mengatasi hal
tersebut, kita dapat menambahkan baris TOTAL dengan query tersendiri.
Jalankan query berikut:
1. SELECT * FROM (
2. SELECT
3. nama, tim,
4. SUM(IF(MONTH(tgl_trx) = 1, nilai_trx, 0)) AS bln_1,
5. COUNT(IF(MONTH(tgl_trx) = 1, id_trx, NULL)) AS trx_1,
6. SUM(IF(MONTH(tgl_trx) = 2, nilai_trx, 0)) AS bln_2,
7. COUNT(IF(MONTH(tgl_trx) = 2, nilai_trx, NULL)) AS trx_2,
8. COUNT(id_trx) AS jml_trx,
9. SUM(nilai_trx) AS total_trx
10. FROM sales3
11. GROUP BY tim, nama
12. ORDER BY total_trx DESC
13. ) AS tabel_sales
14. UNION ALL
15. SELECT 'TOTAL' AS nama, '' AS tim,
16. SUM(IF(MONTH(tgl_trx) = 1, nilai_trx, 0)) AS bln_1,
17. COUNT(IF(MONTH(tgl_trx) = 1, id_trx, NULL)) AS trx_1,
18. SUM(IF(MONTH(tgl_trx) = 2, nilai_trx, 0)) AS bln_2,
19. COUNT(IF(MONTH(tgl_trx) = 2, nilai_trx, NULL)) AS trx_2,
20. COUNT(id_trx) AS jml_trx,
21. SUM(nilai_trx) AS total_trx
22. FROM tabel_sales
Hasil:
Pada contoh diatas, pertama tama kita buat subquery yang berisi rekap
data penjualan yang telah diurutkan berdasarkan kolom total_trx,
selanjutnya, dengan klausa UNION ALL, kita tambahan baris baru yang
berisi TOTAL dari transaksi. Penggunaan klausa UNION ini telah kita bahas
pada BAB 16
Pada kondisi dimana jumlah kolom hasil pivot table berubah ubah, maka
query SQL nya juga ikut berubah, sehingga penggunaan model statis sudah
tidak dapat digunakan lagi, untuk itu, kita perlu menggunakan cara lain
yaitu dengan pivot table dinamis dynamic cross tab.
Untuk membuat pivot table dinamis, kita harus membuat statemen SQL
secara dinamis. Karena SQL merupakan bahasa deklaratif bukan bahasa
prosedural, maka kita tidak bisa membuat perintah SQL secara dinamis
begitu saja, untuk itu, kita perlu “mengakalinya”, caranya, kita buat
perintah SQL menggunakan perintah SQL yang seolah-olah mengambil
data.
Sebagai contoh, mari kita ubah SQL statis yang telah kita bahas pada bagian
sebelumnya menjadi model SQL dinamis, jalankan query berikut:
Hasil:
+------------+---------+---------+
| nama_sales | bln_1 | bln_2 |
+------------+---------+---------+
| Alfa | 375000 | 815000 |
| Bravo | 310000 | 525000 |
| Charlie | 525000 | 300000 |
| Delta | 0 | 1000000 |
| TOTAL | 1210000 | 2640000 |
+------------+---------+---------+
Pada query diatas, jumlah kolom akan terus bertambah jika ada transaksi
di bulan Maret, April, Mei, dst… Jika digambarkan dalam bentuk query
statis, maka query dinamis diatas akan sama seperti query berikut ini:
1. SET @sql_dinamis = (
2. SELECT
3. GROUP_CONCAT( DISTINCT
4. CONCAT('SUM( IF(MONTH(tgl_trx) = '
5. , MONTH(tgl_trx)
6. , ',nilai_trx,0) ) AS bln_'
7. , MONTH(tgl_trx)
8. )
9. )
10. FROM sales3
11. );
Pada contoh diatas, kita simpan query ke dalam variable @sql. Pastikan
isi dari variable tersebut telah sesuai dengan yang kita harapkan.
Jalankan perintah berikut:
SELECT @sql;
3. Eksekusi Query
Setelah query kita susun dengan lengkap, terakhir kita eksekusi query
tersebut. Karena query kita simpan dalam variable, maka kita tidak
bisa langsung mengeksekusinya, melainkan harus kita jalankan
melalui statemen PREPARE kemudian dieksekusi dengan statemen
EXECUTE
1. SET @sql_dinamis = (
2. SELECT
3. GROUP_CONCAT( DISTINCT
4. CONCAT('COUNT( IF(MONTH(tgl_trx) = '
5. , MONTH(tgl_trx)
6. , ', nilai_trx, NULL) ) AS trx_'
7. , MONTH(tgl_trx)
8. , ', SUM( IF(MONTH(tgl_trx) = '
9. , MONTH(tgl_trx)
10. , ', nilai_trx, 0) ) AS bln_'
11. , MONTH(tgl_trx)
12. )
13. )
14. FROM tabel_sales
15. );
16.
17. SET @SQL = CONCAT('SELECT IFNULL(nama, "TOTAL") AS
nama_sales, ',
18. @sql_dinamis, ',
19. COUNT(tgl_trx) AS JML_TRX,
20. SUM(nilai_trx) AS TOTAL
21. FROM sales3
22. GROUP BY nama
23. WITH ROLLUP'
24. );
25.
26. PREPARE stmt FROM @sql;
27. EXECUTE stmt;
28. DEALLOCATE PREPARE stmt;
Pada tabel diatas, dengan fungsi COUNT() kita tambahkan kolom trx_1,
trx_2, dan trx_3. Fungsi ini akan menghitung jumlah baris pada kolom
tgl_trx berdasarkan bulan (baris 4-11). Selain itu, kita juga
menambahkan kolom JML_TRX yang berisi total jumlah transaksi, kolom
tersebut dihasilkan oleh fungsi COUNT(tgl_trx) yang ada pada baris 19.
Terakhir, dengan fungsi SUM(nilai_trx) AS TOTAL (baris 20) kita
tambahkan kolom TOTAL
Jika digambarkan dalam query yang utuh, query diatas akan berbentuk
seperti query berikut:
Untuk membuat index full-text pada kolom, kita gunakan klausa FULLTEXT
ketika membuat tabel, pendefinisian index dilakukan pada level tabel,
contoh kita buat tabel buku dengan index FULLTEXT pada kolom deskripsi
dan primary key pada kolom id_buku:
Jika kita ingin melakukan full-text search pada kolom judul saja atau kolom
deskripsi saja, maka kita dapat membuat index pada masing masing kolom
tersebut, namun jika kita ingin melakukan pencarian full-text pada kedua
kolom tersebut secara bersamaan, kita harus membuat index yang terdiri
dari kedua kolom tersebut, jika tidak, maka akan muncul error ketika
menjalankan query full-text. Jika kita menerapkan ketiganya, maka kita
akan memiliki tiga index, yaitu index untuk kolom judul, kolom deskripsi,
dan kolom judul dan deskripsi.
Untuk membuat index full-text pada tabel yang sudah ada, kita dapat
menggunakan perintah ALTER, misal kita akan menambahkan index full-
text pada kolom (1) judul, (2) kolom deskripsi dan (3) kolom judul dan
deskripsi yang ada pada tabel buku:
Jika ingin menghapus index full-text kita gunakan perintah DROP INDEX,
misal:
Kata yang pendek (kurang dari 4 karakter) akan diabaikan, kita dapat
menentukan jumlah minimum karakter tersebutdengan
mendefinisikan opsi ft_min_word_len sebagai berikut:
[mysqld]
ft_min_word_len = 3
1. SELECT judul
2. FROM buku
3. WHERE MATCH(judul) AGAINST('mysql')
4. LIMIT 3;
Jika kita ingin secara eksplisit mendefinisikan nama mode, kita dapat
menambahkannya pada argumen fungsi AGAINST():
1. SELECT judul
2. FROM buku
3. WHERE MATCH(judul) AGAINST('mysql IN NATURAL LANGUAGE MODE')
4. LIMIT 3;
Jika query diatas dijalankan, maka hasil yang kita peroleh adalah sebagai
berikut:
+----------------------------------------------+
| judul |
+----------------------------------------------+
| Pemrograman Database Menggunakan MySQL |
| PHP dan MySQL Langkah Demi Langkah + CD |
| MySQL Untuk Pemula |
+----------------------------------------------+
1. SELECT judul
2. FROM buku
3. WHERE judul LIKE '%mysql%'
4. LIMIT 3;
Hasil:
+----------------------------------------------+--------------------+
| judul | score |
+----------------------------------------------+--------------------+
| Pemrograman Database Menggunakan MySQL | 0.3184022605419159 |
| PHP dan MySQL Langkah Demi Langkah + CD | 0.3184022605419159 |
| MySQL Untuk Pemula | 0.3184022605419159 |
+----------------------------------------------+--------------------+
Pada contoh diatas, terlihat bahwa score untuk tiap-tiap baris adalah sama,
sehingga baris yang ditampilkan diurutkan apa adanya, sesuai urutan pada
tabel database, hal ini yang membuat hasil pencarian dengan full-text sama
dengan ketika menggunakan operator LIKE.
Hasil:
+----------------------------------------------+---------------------+
| judul | score |
+----------------------------------------------+---------------------+
| PHP dan MySQL Langkah Demi Langkah + CD | 0.7324336171150208 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 0.7324336171150208 |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 0.7324336171150208 |
| Kumpulan Aplikasi PHP untuk Pemula | 0.41403135657310486 |
| Framework PHP Yii 2 | 0.41403135657310486 |
| Pemrograman Database Menggunakan MySQL | 0.3184022605419159 |
| MySQL Untuk Pemula | 0.3184022605419159 |
| Pemrograman Stored Procedure Pada MySQL + cd | 0.3184022605419159 |
+----------------------------------------------+---------------------+
Pada contoh diatas, terlihat bahwa baris dengan score tertinggi akan
ditempatkan di urutan paling atas, score tertinggi diperoleh baris yang
Hasil:
+----------------------------------------------+---------------------+
| judul | score |
+----------------------------------------------+---------------------+
| Pemrograman Database Menggunakan MySQL | 0.3184022605419159 |
| PHP dan MySQL Langkah Demi Langkah + CD | 0.7324336171150208 |
| MySQL Untuk Pemula | 0.3184022605419159 |
| Kumpulan Aplikasi PHP untuk Pemula | 0.41403135657310486 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 0.7324336171150208 |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 0.7324336171150208 |
| Pemrograman Stored Procedure Pada MySQL + cd | 0.3184022605419159 |
| Framework PHP Yii 2 | 0.41403135657310486 |
+----------------------------------------------+---------------------+
Data diatas diurutkan apa adanya sesuai dengan urutan baris pada tabel
dalam database.
Jika data tidak memenuhi kriteria pada pencarian, maka akan memiliki
score 0, misal:
Operator + dan –
Hasil:
judul deskripsi
Pada contoh diatas, full-text search akan mencari data pada tabel buku
yang judul atau deskripsinya mengandung kata mysql, namun tidak
mengandung kata php.
Operator asterik ( * )
1. SELECT judul
2. FROM buku
3. WHERE MATCH(judul) AGAINST('blog*' IN BOOLEAN MODE);
Hasil:
+--------------------------------------+
| judul |
+--------------------------------------+
| Blogger untuk Pemula |
| Ide Bisnis Bermodal Blog |
| Otodidak Membuat Blog dengan Blogger |
+--------------------------------------+
Pada contoh diatas, kita menggunakan operator asterik (*) untuk mencari
semua karakter setelah kata blog, dengan demikian, kata blogger
memenuhi kriteria pencarian. Operator asterik ini hanya bisa ditambahkan
di akhir kata, full-text search akan mengabaikannya jika kita
meletakkannya di depan kata, misal: *sql
Pada boolean mode, operator tanda kutip ganda digunakan untuk mencari
data yang mengandung karakter yang sama persis dengan yang ada di
dalam tanda kutip ganda tersebut, misal, jalankan query berikut:
1. SELECT judul
2. FROM buku
3. WHERE MATCH(judul) AGAINST('"php dan mysql"' IN BOOLEAN MODE);
Hasil:
+----------------------------------------------+
| judul |
+----------------------------------------------+
| PHP dan MySQL Langkah Demi Langkah + CD |
| Pemrograman PHP Dan MySQL Untuk Pemula |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL |
+----------------------------------------------+
Pada contoh diatas, full-text akan mencari data yang mengandung kata
"php dan mysql"
Operator Keterangan
Contoh penggunaan:
'php mysl' Mencari teks yang mengandung kata php atau mysql,
sama seperti klausa OR
'+php +mysql' Mencari teks yang mengandung kata php dan mysql,
sama seperti klausa AND
'+php -mysql' Mencari teks yang mengandung kata php tetapi tidak
mengandung kata mysql.
'+php ~mysql' Mencari teks yang mengandung kata php. Jika teks
tersebut mengandung kata mysql, beri score yang lebih rendah
daripada yang tidak mengandung kata mysql.
'"php dan mysql"' Mencari teks yang mengandung kata sama persis
'php dan mysql'
1. SELECT judul
2. FROM buku
3. WHERE MATCH(judul) AGAINST('php mysql' IN BOOLEAN MODE);
Hasil:
+----------------------------------------------+
| judul |
+----------------------------------------------+
| PHP dan MySQL Langkah Demi Langkah + CD |
| Pemrograman PHP Dan MySQL Untuk Pemula |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL |
| Kumpulan Aplikasi PHP untuk Pemula |
| Framework PHP Yii 2 |
| Pemrograman Database Menggunakan MySQL |
| Pemrograman Stored Procedure Pada MySQL + cd |
| MySQL Untuk Pemula |
+----------------------------------------------+
Pada contoh diatas, karena kita tidak menggunakan operator apapun, full-
text search akan mencari judul yang mengandung kata php atau mysql,
sama seperti mode natural language mode atau tanpa klausa: IN BOOLEAN
MODE WHERE MATCH(judul) AGAINST('php mysql');
Mode terakhir adalah query expansion. Pada mode ini, full-text akan
melakukan pencarian dua kali, yaitu menggunakan natural language mode,
kemudian kata dari hasil pencarian yang paling relevan (score tertinggi)
akan digunakan untuk melakukan pencarian berikutnya.
Hasil:
+----------------------------------------+--------------------+
| judul | score |
+----------------------------------------+--------------------+
| Pemrograman Database Menggunakan MySQL | 2.8319292068481445 |
| Database Systems + CD | 2.7910914421081543 |
+----------------------------------------+--------------------+
Hasil:
+-------------------------------------------------------+--------------------+
| judul | score |
+-------------------------------------------------------+--------------------+
| Pemrograman Database Menggunakan MySQL | 2.900294780731201 |
| Database Systems + CD | 2.7910914421081543 |
| Mudah Menggunakan Internet Untuk Pemula | 1.0428276062011719 |
| Pemrograman PHP Dan MySQL Untuk Pemula | 0.8146394491195679 |
| Pemrograman Stored Procedure Pada MySQL + cd | 0.8146394491195679 |
| From Zero To A Pro: Pemrograman Aplikasi Android + cd | 0.5186294317245483 |
| PHP dan MySQL Langkah Demi Langkah + CD | 0.2960100471973419 |
| MySQL Untuk Pemula | 0.2960100471973419 |
| Trik Kolaborasi ANDROID dengan PHP dan MySQL | 0.2960100471973419 |
+-------------------------------------------------------+--------------------+
Penjelasan:
Terdapat tiga jenis variabel pada MySQL yaitu User-defined variable, local
variable dan system variable. Pada bab ini kita hanya membahas user-
defined variable saja, karena jenis variabel ini yang paling sering
digunakan. Untuk local variabel, dibahas pada BAB Stored Procedure.
5. Jika nilai variabel merupakan hasil dari query, maka query tersebut
harus berada di dalam tanda kurung, misal: SET @total := (SELECT
SUM(nilai_trx) FROM penjualan);
6. Untuk mendeklarasikan lebih dari satu variable, gunakan tanda koma,
misal:
SET @a = 1, @b = 2;
SELECT @a, @b;
atau
SELECT @a := 1, @b := 2;
1. Nilai variable dapat berupa integer, decimal, float, string, atau NULL:
2. Variable hanya dapat diisi satu nilai. Jika nilai tersebut berupa tabel
hasil query, maka tabel tersebut harus terdiri dari satu kolom dan satu
baris, jika tabel terdiri dari lebih dari satu baris, maka akan digunakan
baris terakhir, Misal:
Hasil:
+---------------------+
| @nilai := nilai_trx |
+---------------------+
| 250000 |
| 125000 |
| 215000 |
| 350000 |
| 250000 |
+---------------------+
SELECT @nilai;
Hasil:
+--------+
| @nilai |
+--------+
| 225000 |
+--------+
Karakteristik lain dari variabel ini adalah sekali di deklarasikan, maka akan
dapat digunakan terus hingga session selesai ( koneksi tertutup atau user
logout).
Pada contoh diatas, terlihat bahwa pada perintah kedua, MySQL akan
menampilkan tabel yang berisi nilai dari variable @website, pada saat yang
sama, MySQL juga menyimpan nama dan nilai variabel tersebut, mari kita
tes dengan memanggil variable @website:
Contoh lain:
Pada query diatas, pertama tama kita deklarasikan variabel @no dengan
nilai 0, selanjutnya, pada statement SELECT, variabel tersebut kita sertakan
pada hasil query sehingga, setiap kali variabel tersebut dieksekusi, nilainya
akan selalu bertambah satu @no := @no + 1, sehingga akan membentuk
data nomor urut.
Query diatas masih berupa dua statement, pada kondisi tertentu kita perlu
membuatnya menjadi satu statemen, untuk keperluan tersebut, kita dapat
mendeklarasikan variabel pada bagian klausa FROM:
Pada query diatas, pertama tama MySQL akan menyimpan nilai variabel
@no, hal ini dikarenakan setiap kali menjalankan statemen SELECT,
pertama kali yang dieksekusi adalah klausa FROM, selanjutnya, variabel @no
tersebut di gunakan oleh klausa SELECT
1. SELECT * FROM (
2. SELECT @no := @no + 1 AS peringkat,
3. nama,
4. nilai
5. FROM (SELECT @no := 0) AS tml_table, ujian
6. ORDER BY nilai DESC
7. ) AS tmp_table
8. WHERE peringkat BETWEEN 3 AND 5
Hasil;
+-----------+-------+-------+
| peringkat | nama | nilai |
+-----------+-------+-------+
| 3 | Delta | 81 |
| 4 | Echo | 79 |
| 5 | Bravo | 78 |
+-----------+-------+-------+
Pada contoh diatas, nilai rata-rata kita simpan terlebih dahulu pada
variabel @rata_rata, selanjutnya kita bandingkan nilai pada masing
masing baris dengan nilai pada variabel @rata_rata, hasilnya kita
masukkan ke dalam kolom keterangan.
Pada tabel diatas, total penjualan s.d bulan Januari adalah 175.000, s.d
bulan Februari adalah 735.000 (175.000 + 560000), dan total penjualan s.d
bulan Maret adalah 1.850.000 (175.000 + 560000 + 550000). Pada query
diatas, pertama tama MySQL akan menjalankan subquery:
Selanjutnya, pada query utama, MySQL akan mengambil data kolom bulan,
jml_trx, dan total_trx, kemudian pada bagian @x:= @x + total_trx,
Selanjutnya, kita jalankan query untuk menampilkan data kolom nama dan
tgl_trx pada tabel sales2
Hasil:
+---------+----------+
| nama | @tgl_trx |
+---------+----------+
| Alfa | tgl_trx |
| Charlie | tgl_trx |
| Bravo | tgl_trx |
| Bravo | tgl_trx |
| Alfa | tgl_trx |
+---------+----------+
Pada contoh diatas, kolom @tgl_trx akan berisi nilai dari variabel @tgl_trx
yaitu string 'tgl_trx' bukan isi dari kolom tgl_trx. Demikian juga untuk
nama tabel, jika nama tabel kita simpan pada variable, maka ketika
dijalankan akan muncul pesan error, misal:
Karena hasil query dari view berupa tabel yang tidak tersimpan pada
database, maka view ini sering disebut dengan tabel virtual atau virtual
table, meski demikian, MySQL juga menganggap view ini sebagai tabel
sehingga tetap dapat terlihat ketika kita menjalankan perintah SHOW
TABLES, disamping itu, pesan error atau warning terkait view akan di di
tampilkan seperti error pada tabel umumnya.
SELECT C1.1,
C1.3,
C2.2,
C3.2,
C3.3
C1.1 C1.2 C1.3 C2.1 C2.2 C2.3 C3.1 C3.2 C3.3
FROM `Tabel 1`
LEFT JOIN `Tabel 2`
ON C1.1 = C2.1
LEFT JOIN `Tabel 3`
ON C1.1 = C3.1
WHERE C2.1 = 'AKTIF'
ORDER BY C.2.2
Tabel 2 Tabel 2 Tabel 3 LIMIT 10
BASE TABLE
4. View dapat membatasi data (kolom) apa saja yang akan kita
tampilkan ke user lain. Ketika membuat view, kita dapat memilih
kolom apa saja yang akan kita tampilkan pada view, sehingga dapat
menjaga agar data sensitif tidak ter ekspose ke luar. Pada MySQL,
Administrator dapat memberi akses ke user agar hanya dapat
mengakses view tidak pada tabel riil.
5. Tidak memakan tempat. Karena hanya query, bukan tabel riil, maka
tidak ada data yang disimpan oleh view, sehingga tidak memakan
tempat pada database
1. CREATE
2. VIEW nama_view
3. AS statemen_select
Setelah view dibuat, maka untuk menampilkan data yang ada pada
statemen_select kita cukup memanggil nama_view tersebut, sebagai
contoh kita memiliki tabel berikut:
Tabel pelanggan
+--------------+----------+--------------------+
| id_pelanggan | nama | email |
+--------------+----------+--------------------+
| 1 | Anton | anton@gmail.com |
| 2 | Braskie | braskie@yahoo.com |
| 3 | Charlie | charlie@gmail.com |
| 4 | Deni | deni@gmail.com |
+--------------+----------+--------------------+
Tabel penjualan
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 2 | 3 | 2017-03-22 | 395000 |
Tabel retur
+----------+--------+--------------+------------+-------------+
| id_retur | id_trx | id_pelanggan | tgl_retur | nilai_retur |
+----------+--------+--------------+------------+-------------+
| 1 | 2 | 2 | 2017-03-29 | 175000 |
| 2 | 7 | 4 | 2017-03-21 | 215000 |
+----------+--------+--------------+------------+-------------+
1. CREATE
2. VIEW penjualan_view
3. AS SELECT id_trx,
4. nama AS nama_pelanggan,
5. tgl_trx,
total_trx,
6.
tgl_retur,
7. nilai_retur
8. FROM penjualan
9. LEFT JOIN pelanggan USING(id_pelanggan)
10. LEFT JOIN retur USING(id_trx)
11. ORDER BY tgl_trx DESC
2. Hasil query ketika membuat view akan berbentuk tetap dan tidak
terpengaruh pada perubahan struktur tabel. Misal jika view dibuat
untuk menampilkan semua kolom SELECT * FROM penjualan, maka
6. Sebelum MySQL versi 5.7.7, klausa FROM yang ada pada statemen
SELECT tidak dapat mengandung subquery, misal: SELECT * FROM
(SELECT … ) AS temp
7. Pada statemen SELECT yang ada di dalam view, kita bisa menggunakan
klausa ORDER BY, namun, ketika kita memanggil view dengan
mendefinisikan ORDER BY tersendiri, maka ORDER BY pada view
tersebut akan diabaikan.
Pada tabel diatas terlihat bahwa kolom nama pada tabel pelanggan
berubah menjadi nama_pelanggan, hal ini dikarenakan pada saat membuat
view, kita gunakan alias nama_pelanggan (nama AS nama_pelanggan)
pada kolom tersebut. Jika saat membuat view kita gunakan alias pada
kolom, maka ketika memanggil view, kita tidak dapat memanggil nama asli
dari kolom tersebut, melainkan harus menggunakan nama aliasnya, jika
tidak, akan muncul pesan error bahwa kolom tidak ditemukan: SQL Error
(1054): Unknown column 'nama' in 'field list
1. SELECT *
2. FROM penjualan_view
3. WHERE tgl_retur IS NOT NULL
Hasil:
+--------+----------------+------------+-----------+------------+-------------+
| id_trx | nama_pelanggan | tgl_trx | total_trx | tgl_retur | nilai_retur |
+--------+----------------+------------+-----------+------------+-------------+
| 2 | Charlie | 2017-03-22 | 395000 | 2017-03-29 | 175000 |
| 7 | Braskie | 2017-03-05 | 215000 | 2017-03-21 | 215000 |
+--------+----------------+------------+-----------+------------+-------------+
Kita juga dapat melakukan berbagai fungsi agregasi seperti pada tabel riil.
Misal kita buat resume data order yang sukses (order yang tidak memiliki
retur). Query yang kita jalankan:
1. SELECT nama_pelanggan,
2. COUNT(tgl_trx) AS jml_trx,
3. SUM(total_trx) AS total
Hasil:
+----------------+---------+--------+
| nama_pelanggan | jml_trx | total |
+----------------+---------+--------+
| Charlie | 3 | 851000 |
| Braskie | 1 | 360000 |
| Anton | 1 | 269000 |
| Deni | 1 | 110000 |
+----------------+---------+--------+
1. CREATE
2. OR REPLACE
Pada contoh diatas, ketika kita panggil view penjualan_view, tabel yang
dihasilkan tidak lagi sama seperti contoh sebelumnya melainkan berubah
sesuai dengan view yang baru.
1. CREATE
2. VIEW nama_view
3. (kolom1, kolom2, kolom2, ...)
4. AS statemen_select
Misal kita ubah view penjualan_view seperti yang telah kita buat pada
contoh sebelumnya dengan mendefinisikan nama kolom sebagai berikut:
Jika terjadi perubahan pada struktur base tabel, misal nama kolom
berubah, maka view tidak dapat digunakan lagi, misal pada tabel
penjualan, kita ganti kolom id_pelanggan menjadi id_plg, maka ketika kita
jalankan perintah SELECT * FROM penjualan_view, maka akan muncul
pesan error:
Setelah query diatas kita jalankan, kita tidak dapat lagi mengakses view
penjualan_view (akan muncul pesan error bahwa tabel tidak
ditemukan) SQL Error (1146): Table 'toko_buku.penjualan_view'
doesn't exist
1. ALTER
2. VIEW pelanggan_order
3. AS SELECT pelanggan.id_pelanggan, nama, id_trx,
tgl_trx, total_trx
4. FROM penjualan
5. LEFT JOIN pelanggan USING(id_pelanggan)
Jika view tidak ditemukan, maka akan muncul pesan error yang
menandakan bahwa tabel (view) tidak ditemukan. Misal kita akan
menghapus view pelanggan_retur dan pelanggan_order, dimana view
pelanggan_retur sebenarnya tidak ada.
Perbedaan ERROR dan WARNING adalah, jika error, maka script akan
berhenti, proses eksekusi tidak diteruskan ke script berikutnya, jika
warning, maka proses eksekusi akan tetap diteruskan ke script
berikutnnya.
Hasil:
+---------------------+------------+
| Tables_in_toko_buku | Table_type |
+---------------------+------------+
| pelanggan_order | VIEW |
+---------------------+------------+
Tabel terdiri dari dua jenis/tipe yaitu BASE TABLE dan VIEW. Pada query
diatas, penulis menambahkan WHERE table_type = 'view' untuk
menampilkan tabel yang berjenis VIEW.
Terkadang kita juga ingin mengetahui query apa yang ada pada suatu view.
Untuk keperluan tersebut, kita dapat menggunakan perintah SHOW CREATE
VIEW. Misal kita ingin menampilkan view pelanggan_order
*************************** 1. row
***************************
View: pelanggan_order
Create View: CREATE VIEW "pelanggan_order" AS
select "pelanggan"."id_pelanggan" AS
"id_pelanggan","pelanggan"."nama" AS
"nama","penjualan"."id_trx" AS
"id_trx","penjualan"."tgl_trx" AS
"tgl_trx","penjualan"."total_trx" AS "total_trx" from
("penjualan" left join "pelanggan"
on(("penjualan"."id_pelanggan" =
"pelanggan"."id_pelanggan")))
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
1 row in set (0.00 sec)
Disamping itu, kita juga dapat melihat struktur dari view melalui database
information_schema dengan query sebagai berikut:
1. SELECT VIEW_DEFINITION
2. FROM INFORMATION_SCHEMA.VIEWS
3. WHERE TABLE_SCHEMA = 'toko_buku' AND TABLE_NAME =
'pelanggan_order';
Hasil:
select `toko_buku`.`pelanggan`.`id_pelanggan` AS
`id_pelanggan`,`toko_buku`.`pelanggan`.`nama` AS
`nama`,`toko_buku`.`penjualan`.`id_trx` AS
`id_trx`,`toko_buku`.`penjualan`.`tgl_trx` AS
`tgl_trx`,`toko_buku`.`penjualan`.`total_trx` AS `total_trx`
from (`toko_buku`.`penjualan` left join
4. Mengandung JOIN
5. Klausa FROM mengandung view yang tidak updateable atau terdiri dari
dua atau lebih tabel.
1. CREATE
2. VIEW penjualan_maret
3. AS SELECT id_trx,
4. id_pelanggan,
5. tgl_trx,
6. total_trx
7. FROM penjualan
8. WHERE MONTH(tgl_trx) = 3
Seperti yang telah kita bahas sebelumnya, bahwa perubahan data pada
view sejatinya adalah perubahan data pada base table. Untuk itu, mari kita
cek data pada tabel penjualan, jalankan perintah berikut:
Dari tabel diatas terlihat bahwa pada tabel penjualan, data dengan id_trx
2, tgl_trx nya berubah menjadi 2017-02-22. Selain UPDATE, Anda dapat
mencoba statemen INSERT atau DELETE untuk mengubah data pada view
penjualan_maret.
Selanjutnya, mari kita cek data pada view, kita jalankan kembali perintah
SELECT * FROM penjualan_maret, hasil yang kita peroleh:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 4 | 1 | 2017-03-04 | 269000 |
| 6 | 3 | 2017-03-07 | 256000 |
| 7 | 2 | 2017-03-05 | 215000 |
+--------+--------------+------------+-----------+
Dari data tersebut, terlihat bahwa data dengan id_trx 2 sudah tidak ada
karena tidak termasuk transaksi bulan Maret. Pada kondisi tertentu, kita
tidak ingin hal tersebut terjadi, untuk itu, kita dapat mencegahnya dengan
menggunakan klausa WITH CHECK OPTION.
Dengan klausa WITH CHECK OPTION, ketika terjadi perubahan data, maka
akan dilakukan pengecekan apakah data tersebut memenuhi kriteria pada
klausa WHERE yang ada pada statemen SELECT yang ada pada view, jika
tidak memenuhi, maka akan muncul pesan error. Disamping itu juga
dilakukan pengecekan apakah setelah dilakukan perubahan, data tersebut
akan hilang pada tabel view, jika ya maka akan muncul pesan error.
Selanjutnya, pada data dengan id_trx 2 , kita ubah tgl_trx nya menjadi 2017-
02-22, jalankan query berikut:
1. UPDATE penjualan_maret
2. SET tgl_trx = '2017-02-22'
3. WHERE id_trx = 2
Ketika menjalankan query tersebut, kita akan memperoleh pesan error SQL
Error (1369): CHECK OPTION failed 'toko_buku.penjualan_maret',
hal tersebut dikarenakan tgl_trx yang baru tidak memenuhi kriteria WHERE
MONTH(tgl_trx) = 3.
Klausa WITH CHECK OPTION sendiri memiliki dua opsi yaitu CASCADED dan
LOCAL. Jika kita tidak mendefinisikan opsi, maka MySQL otomatis akan
menggunakan opsi CASCADED.
Seperti yang telah kita bahas sebelumnya, view dapat dibuat berdasarkan
view lain, dengan opsi CASCADE, MySQL akan mengecek apakah perubahan
data tersebut sesuai dengan kriteria yang ada pada view yang sedang
dijalankan maupun view yang menjadi tabel referensi.
Pada query diatas kita tambahkan klausa WITH CASCADED CHECK OPTION
yang sebenarnya juga bisa ditulis tanpa cascaded. Kita tambahkan
CASCADED untuk memperjelas jenis CHECK OPTION nya.
selanjutnya data dengan id_trx 4 kita ubah tgl_trx nya menjadi 2017-02-22,
query yang kita jalankan:
1. UPDATE penjualan_maret_kecil
2. SET tgl_trx = '2017-02-22'
3. WHERE id_trx = 4
Ketika query tersebut dijalankan, kita akan mendapati pesan error: SQL
Error (1369): CHECK OPTION failed
Opsi kedua dari WITH CHECK OPTION ini adalah LOCAL, dengan opsi LOCAL,
MySQL hanya akan mengecek kriteria pada klausa WHERE yang ada pada
view yang sedang berjalan, dan tidak mengecek pada view yang digunakan
sebagai referensi.
Dengan WITH CHECK OPTION kita akan mengetahui apakah suatu view
updateable atau tidak, yang berarti view tersebut dapat diupdate secara
aman, namun demikian view yang tidak memenuhi kriteria updateable
juga dapat kita ubah datanya, namun tidak ada jaminan adanya integritas
data.
Stored Routines terdiri dari dua yaitu Stored Procedure dan Stored
Function. Pada BAB ini, kita akan membahas tentang Stored Procedure,
sedangkan Stored Function akan kita bahas pada BAB berikutnya.
Pada bab sebelumnya kita telah membahas view. Mungkin Anda bertanya
apa beda view dengan SP? Bedanya, view merupakan sebuah tabel virtual
dimana kita dapat menggunakannya pada statemen lain, seperti statemen
SELECT, sedangkan SP merupakan statemen tersendiri yang langsung
menghasilkan output yang berdiri sendiri, sehingga tidak bisa digunakan
bersama dengan statemen lain.
Hanya perlu di tulis sekali dan dapat dijalankan dimana saja, tanpa
perlu menulis ulang kode SQL, yang bisa jadi kode tersebut kompleks.
Membatasi hak akses user. Misal kita memiliki beberapa tabel dan kita
tidak ingin user mengakses tabel tersebut, dengan SP kita dapat
menyamarkan tabel tersebut dan cukup memberi hak akses EXECUTE
(untuk memanggil SP) kepada user dan tidak memberi hak akses ke
tabel.
Beban server CPU. Jika kita banyak menggunakan ekspresi logika pada
SP, maka beban server untuk memproses SP tersebut akan bertambah,
karena SQL merupakan bahasa deklaratif, sehingga kurang maksimal
ketika memproses ekspresi logika
1. DELIMITER $
2. CREATE PROCEDURE penjualan()
3. BEGIN
4. SELECT * FROM penjualan;
5. END $
6. DELIMITER ;
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan_all $
3. CREATE PROCEDURE penjualan_all()
4. BEGIN
5. SELECT * FROM penjualan;
6. END $
7. DELIMITER ;
Perhatikan bahwa pada contoh diatas, pada baris 2 kita gunakan tanda $
sebagai akhir dari statemen DROP PROCEDURE
Parameter pada SP ini mirip dengan argumen pada fungsi yang digunakan
oleh bahasa pemrograman pada umumnya, seperti PHP. Parameter ini
berupa suatu nilai yang diisikan ketika kita memanggil SP, selanjutnya nilai
tersebut dapat digunakan oleh statemen yang ada di dalam SP.
1. SELECT *
2. FROM penjualan
3. WHERE MONTH(tgl_trx) = parameter
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan $
3. CREATE PROCEDURE penjualan (month INT)
4. BEGIN
5. SELECT *
6. FROM penjualan
7. WHERE MONTH(tgl_trx) = month;
8. END $
9. DELIMITER ;
Pada contoh diatas, penulis memberi nama parameter dengan nama month
(Anda bebas memberi nama lain), selanjutnya kita tambahkan INT untuk
menandakan bahwa parameter tersebut memiliki tipe data integer. Perlu
dicatat bahwa jenis tipe data ini harus kita isikan, jika tidak, maka SP tidak
akan bisa dibuat.
Pada tipe data tertentu, kita harus mendefinisikan panjang data. Pada
contoh diatas, kita boleh tidak menuliskan panjang data pada tipe data IN,
karena MySQL akan otomatis memberi nilai 11 (panjang data maksimal).
Untuk tipe data lain seperti character, maka kita harus mendefinisikan
panjang datanya, misal VARCHAR(255) atau CHAR(50)
Perlu diperhatikan juga bahwa pada SP terdapat tiga jenis parameter yaitu
IN, OUT, dan INOUT. Pada contoh diatas, kita gunakan parameter berjenis
IN, dimana ketika memanggil SP, kita memberikan (memasukkan)
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan $
3. CREATE PROCEDURE penjualan (
4. bulan INT,
5. nama_pelanggan VARCHAR(255)
)
6.
BEGIN
7. SELECT id_pelanggan, nama, tgl_trx, total_trx
8. FROM penjualan
9. LEFT JOIN pelanggan USING (id_pelanggan)
10. WHERE MONTH(tgl_trx) = bulan
11. AND nama = nama_pelanggan;
12. END $
13. DELIMITER ;
Perlu diperhatikan bahwa kita juga tidak boleh memberi nama parameter
sama dengan nama kolom pada tabel yang digunakan pada SP, misal pada
contoh diatas, parameter kedua penulis beri nama nama_pelanggan bukan
nama saja, karena akan sama dengan kolom nama yang ada pada tabel
pelanggan.
CALL penjualan_all
atau
CALL penjualan_all()
Jika kita tidak mengisikan nilai parameter, maka akan muncul pesan error.
Perhatikan bahwa tipe data parameter pertama SP penjualan adalah
integer (INT), pada contoh diatas, kita isikan nilai 3 (integer – tipe data
sesuai), namun demikian kita dapat mengisikan nilai dengan tipe data lain,
misal string seperti pada contoh berikut:
Hal ini dikarenakan MySQL akan melakukan type casting yang akan
mengubah nilai inputan string menjadi integer.
Ketika memanggil SP, kita juga dapat menyertakan nama database, misal
CALL toko_buku.penjualan(3, 'Charlie'), hal ini kita lakukan jika SP
yang kita panggil tidak berada di dalam default database yang sedang kita
gunakan
Selanjutnya, jika SP penjualan kita jalankan, hasil yang kita peroleh adalah:
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan_total $
3. CREATE PROCEDURE penjualan_total(
4. bulan INT,
5. OUT total INT
BEGIN
6.
SELECT SUM(total_trx)
7. INTO total
8. FROM penjualan
9. WHERE MONTH(tgl_trx) = bulan;
10. END $
11. DELIMITER ;
Pada query diatas, kita simpan hasil dari stored procedure ke dalam
variabel @total_penjualan. Selanjutnya ketika kita tampilkan data
variabel @total_penjualan maka akan berisi nilai total transaksi bulan 2
yaitu sebesar 1.135.000
Pada SP, kita juga dapat menghasilkan nilai output lebih dari satu, misal,
melanjutkan contoh sebelumnya, kita ubah stored procedure
penjualan_total sehingga menghasilkan output nilai total penjualan
dan total jumlah transaksinya, query yang kita jalankan:
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan_total_jumlah $
3. CREATE PROCEDURE penjualan_total_jumlah (
4. bulan INT,
5. OUT total INT,
6. OUT jml_trx INT
7. )
8. BEGIN
9. -- total
10. SELECT SUM(nilai_trx)
11. INTO total
12. FROM penjualan
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan_total $
3. CREATE PROCEDURE penjualan_total (
4. bulan INT,
5. OUT total INT,
OUT jml_trx INT
6.
)
7. BEGIN
8. SELECT SUM(total_trx), COUNT(id_trx)
9. INTO total, jml_trx
10. FROM penjualan
11. WHERE MONTH(tgl_trx) = bulan;
12. END $
13. DELIMITER ;
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS penjualan_akumulatif $
3. CREATE PROCEDURE penjualan_akumulatif (
4. INOUT total INT,
5. OUT total_asli INT
6. )
7. BEGIN
8. SET total_asli = ( SELECT SUM(total)
9. FROM penjualan
10. );
11. SET total = total + total_asli;
12. END $
13. DELIMITER ;
Untuk tipe data yang sama, kita dapat menggabungkannya dalam satu
deklarasi, misal:
Pada deklarasi diatas, semua variabel yang kita deklarasikan memiliki nilai
awal NULL, kita dapat mengubah nilai awal tersebut (nilai default) dengan
menambahkan klausa DEFAULT, misal:
Sebagai contoh, misal kita buat SP dengan nama harga_neto yang akan
menghasilkan harga neto dari barang setelah diskon, Query yang kita
jalankan:
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS harga_neto $
3. CREATE PROCEDURE harga_neto(
4. IN id INT,
5. OUT harga_neto INT
6. )
7. BEGIN
8. DECLARE nilai_diskon FLOAT;
9. SET nilai_diskon = ( SELECT diskon
10. FROM diskon
11. WHERE id_kategori = 0
12. AND expired > NOW()
13. );
14. SELECT harga - (harga * nilai_diskon)
15. INTO harga_neto
16. FROM buku
17. WHERE id_buku = id;
18. END $
Harga awal adalah 59.000 setelah dikurang diskon 10% menjadi 53.100
Jika kita menggunakan model user variable, kita tidak perlu menggunakan
statemen DECLARE, misal pada query diatas kita definisikan variabel
nilai_diskon dengan statemen SET:
1. BEGIN
2. SET @nilai_diskon = ( SELECT diskon
3. FROM diskon
4. WHERE id_kategori = 0
5. AND expired > NOW()
6. );
7. ...
8. END $
Pada format diatas, statemen yang ada di dalam tanda kurung siku yaitu
ELSEIF dan ELSE sifatnya opsional, tidak harus ada.
1. DELIMITER $
2. CREATE DEFINER=`root`@`localhost` PROCEDURE `harga_neto2`(
3. IN `id` INT,
4. OUT `harga_awal` INT,
5. OUT `harga_neto` INT,
6. OUT `diskon` DECIMAL(10,2)
7.
8. )
9.
10. BEGIN
11. DECLARE kategori INT;
12. DECLARE nilai_diskon FLOAT;
13.
14. SET kategori = (SELECT id_kategori
15. FROM buku
16. WHERE id_buku = id );
17.
18. -- diskon (OUT)
19. IF kategori = 1
20. THEN SET nilai_diskon = 0.2;
Query diatas menghasilkan output harga awal, harga diskon, dan nilai
diskon. Penjelasan:
Pada baris 14 kita cari id_kategori dari buku yang memiliki id_buku 1,
hasilnya kita simpan pada variabel kategori.
Pada baris 19 s.d 26, berdasarkan nilai pada variabel kategori, kita
cari besarnya nilai diskon.
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE
Selain cara diatas, terdapat bentuk lain penulisan statemen CASE, yaitu:
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE
cara kedua ini umumnya kita gunakan untuk menuliskan CASE pada
statemen SELECT.
Karena memiliki alur yang mudah dipahami, cara pertama lebih pas
digunakan jika kita ingin melakukan pengujian satu nilai, seperti
penggunaan fungsi IF pada statemen SELECT. Sedangkan cara kedua lebih
mirip dengan statemen IF dimana kita menguji kondisi yang berbeda beda.
Misal pada contoh sebelumnya, kita ubah SP harga_neto2 menggunakan
statemen CASE bentuk pertama:
1. CASE
2. WHEN kategori = 1 THEN SET nilai_diskon = 0.2;
3. WHEN kategori = 2 THEN SET nilai_diskon = 0.15;
4. WHEN kategori = 3 THEN SET nilai_diskon = 0.1;
5. ELSE SET nilai_diskon = 0.08;
6. END CASE;
COMMENT 'string'
LANGUAGE SQL
[NOT] DETERMINISTIC
Karakteristik ditulis tidak harus urut sesuai urutan diatas, disamping itu,
kita juga dapat menggunakan karakteristik tertentu sesuai kebutuhan,
misal hanya menggunakan COMMENT.
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS `harga_neto2` $
3. CREATE DEFINER=`root`@`localhost` PROCEDURE
4. `harga_neto2`(
5. IN `id` INT,
6. OUT `harga_awal` INT,
7. OUT `harga_neto` INT,
8. OUT `diskon` DECIMAL(10,2)
9. )
10. LANGUAGE SQL
11. NOT DETERMINISTIC
12. CONTAINS SQL
13. SQL SECURITY DEFINER
COMMENT 'Stored Procedure yang digunakan untuk
menghitung harga neto setelah dikurangi diskon'
14. BEGIN
15. ...
16. END $
17. DELIMITER ;
Ketika kita jalankan perintah tersebut, data yang ditampilkan kurang lebih
sebagai berikut:
+-----------------+-----------------------+-----------+----------------+
| Db | Name | Type | Definer |
+-----------------+-----------------------+-----------+----------------+
| tutorial | penjualan_akumulatif | PROCEDURE | root@localhost |
| tutorial | penjualan_total_bulan | PROCEDURE | root@localhost |
| shop | sales_neto | PROCEDURE | root@localhost |
| shop | sales_month | PROCEDURE | root@localhost |
+-----------------+-----------------------+-----------+----------------+
Lanjutan…
+---------------------+---------------------+---------------+---------+
| Modified | Created | Security_type | Comment |
+---------------------+---------------------+---------------+---------+
| 2017-03-18 05:14:50 | 2016-03-18 05:14:50 | DEFINER | |
| 2017-03-18 20:42:18 | 2016-03-18 20:42:18 | DEFINER | |
| 2017-03-18 17:20:53 | 2016-03-18 17:20:53 | DEFINER | |
| 2017-03-18 19:47:05 | 2016-03-18 19:47:05 | DEFINER | |
+---------------------+---------------------+---------------+---------+
Atau jika kita ingin menampilkan nama procedure yang mengandung kata
tertentu, kita bisa menggunakan operator LIKE, misal kita tampilkan SP
yang mengandung kata order:
Jika kita ingin menampilkan query yang ada pada stored procedure, kita
dapat menggunakan perintah:
-- diskon (OUT)
CASE kategori
WHEN 1 THEN SET nilai_diskon = 0.2;
WHEN 2 THEN SET nilai_diskon = 0.15;
WHEN 3 THEN SET nilai_diskon = 0.1;
Pada query diatas, penulis mengubah sql_mode menjadi ANSI agar hasil
yang ditampilkan lebih mudah dibaca.
COMMENT 'string'
LANGUAGE SQL
{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
SQL SECURITY { DEFINER | INVOKER }
Untuk mengubah parameter atau isi dari SP, kita harus menghapus SP
tersebut dengan statemen DROP, baru kemudian kita buat SP baru dengan
nama yang sama, seperti yang kita lakukan pada beberapa contoh
sebelumnya.
Pada BAB sebelumnya kita telah membahas Stored Routines yang pertama
yang itu Stored Procedure, pada BAB ini, kita akan membahas Stored
Routines yang kedua yaitu Stored Function.
Stored Function atau SF adalah fungsi (function) yang dibuat oleh user
yang disimpan (stored) dalam database. Mirip dengan Stored Procedure
(SP), SF juga bermanfaat untuk menyederhanakan syntax SQL yaitu cukup
dengan memanggil statemen tertentu saja, tidak perlu menulis berulang
ulang query yang kompleks.
SF sama halnya dengan fungsi bawaan SQL seperti SUM, COUNT, dll
sehingga dapat digabung dengan statemen lain, misal: SELECT
SF(..), SUM(..)
Parameter boleh untuk tidak diisi. Kita tidak bisa menyertakan IN, OUT,
maupun INOUT pada parameter, semua parameter secara implisit
bersifat IN
Isi dari fungsi (antara BEGIN dan END) harus mengandung setidaknya
satu statemen RETURN (tidak ada tambahan S), yang digunakan untuk
menghentikan eksekusi fungsi dan mengembalikan hasil kepada
pemanggil fungsi.
1. DELIMITER $
2. DROP FUNCTION IF EXISTS total_perbulan $
3. CREATE FUNCTION total_perbulan(bulan INT, tahun INT)
4. RETURNS INT
5. BEGIN
6. RETURN (SELECT SUM(total_trx)
7. FROM penjualan
8. WHERE MONTH(tgl_trx) = bulan
9. AND YEAR(tgl_trx) = tahun
10. );
11. END $
12. DELIMITER ;
Hasilnya:
+--------------+
| total_3_2017 |
+--------------+
| 1135000 |
+--------------+
Lebih lanjut, ketika membuat SF kita juga dapat menambahkan definer dan
parameter tambahan seperti COMMENT, LANGUAGE, DETERMINISTIC, dll,
format lengkapnya adalah sebagai berikut:
1. DELIMITER $
2. DROP FUNCTION IF EXISTS status_stok $
3. CREATE FUNCTION status_stok(jml_stok INT)
4. RETURNS VARCHAR(50)
5. BEGIN
6.
7. SET @nama_status = "KOSONG";
Ketika perintah tersebut kita jalankan, maka akan muncul data kurang
lebih seperti tabel berikut:
+-----------+----------------+----------+----------------+
| Db | Name | Type | Definer |
+-----------+----------------+----------+----------------+
| toko_buku | status_stok | FUNCTION | root@localhost |
| toko_buku | total_perbulan | FUNCTION | root@localhost |
+-----------+----------------+----------+----------------+
Lanjutan:
Seperti query tabel pada umumnya, kita dapat memfilter data tersebut
menggunakan klausa WHERE, misal kita ingin menampilkan SF yang ada
pada database toko_buku yang mengandung kata status, maka kita
gunakan perintah:
Untuk menampilkan detail dari suatu SF termasuk isi dari SF tersebut, kita
gunakan perintah berikut:
Misal kita ingin menampilkan detail dari SF status_stok, hasil yang kita
peroleh adalah sebagai berikut:
IF jml_stok >= 10
THEN SET @nama_status = 'BANYAK';
ELSE IF jml_stok <= 9 AND jml_stok >=3
THEN SET @nama_status = 'CUKUP';
ELSE IF jml_stok > 0 AND jml_stok <= 2
THEN SET @nama_status = 'SEDIKIT';
END IF;
Pada contoh diatas penulis mengubah sql_mode menjadi ANSI agar hasil
yang ditampilkan lebih mudah dibaca.
Namun sama seperti pada Stored Procedure, kita tidak dapat merubah
nama maupun isi dari SF, solusinya, terlebih dahulu kita hapus SF tersebut
dengan statemen DROP baru kemudian kita buat SF baru dengan nama yang
sama.
Kita juga dapat menambahkan nama database pada nama fungsi sebagai
berikut:
Jika nama database tidak didefinisikan, maka MySQL akan secara implisit
menambahkan nama database yang sedang digunakan.
Misal:
Ketika memilih apakah menggunakan SP atau SF, hal mendasar yang perlu
diperhatikan adalah bahwa Stored Function hanyalah fungsi seperti fungsi
MySQL pada umumnya, misal: fungsi SUM dan COUNT, sehingga perannya
hanya sebagai pelengkap dan tidak dapat berdiri sendiri, untuk
menjalankannya selalu membutuhkan statemen induk seperti SELECT,
sebaliknya, Stored Procedure, meruakan statemen yang berdiri sendiri
yang dipanggil menggunakan statemen CALL
Kesimpulannya, jika Stored Routine yang kita buat bertujuan hanya untuk
mengolah data spesifik (tanpa memanipulasi data pada database) dan hasil
pengolahan tersebut langsung dapat digunakan, maka gunakan Stored
Function, sedangkan jika Stored Routines yang kita gunakan bertujuan
untuk memanipulasi data pada tabel database (menggunakan statemen
INSERT, UPDATE, DELETE, dll), gunakan Stored Procedure.
Terdapat data daftar transaksi per buku per pelanggan yang akan
disimpan pada tabel penjualan_detail. Data tersebut merinci buku
apa saja yang dibeli oleh pelanggan.
Terakhir, kita update stok buku yang ada pada tabel buku dengan
mengurangkan jumlah stok dengan jumlah buku yang terjual.
Dari ketiga tahapan diatas dapat kita bayang jika salah satu dari tahapan
tersebut gagal dieksekusi, maka data yang di sajikan menjadi tidak akurat.
Misal data stok buku gagal diupdate, maka pada transaksi berikutnya,
untuk buku yang seharusnya stok nya habis, buku tersebut tetap dapat
dibeli. Pada kondisi demikian maka kita harus memastikan bahwa ketiga
statemen diatas harus berhasil dieksekusi, disinilah peran Transaksi.
Dengan Transaction, jika tahap pertama dan kedua berhasil, namun tahap
ke tiga gagal, maka keseluruhan proses dapat dibatalkan dan data yang
telah di masukkan ke tabel dapat dibatalkan (ROLLBACK), jika keseluruhan
tahap berhasil maka semua data akan disimpan secara permanen
(COMMIT)
Dari contoh diatas, dapat kita simpulkan bahwa salah satu manfaat
terpenting dari transaction ini adalah untuk menjaga integritas data, yang
Lebih jauh, sistem Transaksi pada database memiliki properti ACID (ACIF
Property), yaitu: Atomic, Consistent, Durable, dan Isolated. Adapun
penjelasannya adalah sebagai berikut:
Atomic
Memastikan bahwa semua proses berhasil di eksekusi, jika ada yang gagal,
maka semua proses dibatalkan dan semua data yang telah berubah
dikembalikan ke kondisi semula, atau lebih simpelnya: semua atau tidak
sama sekali
Consistency
Isolation
Isolation atau isolasi berarti ketika terjadi transaksi maka data yang
sedang diakses, akan di isolir sehingga tidak bisa di akses oleh operasi lain,
untuk dapat mengakses data tersebut, harus menunggu operasi pertama
selesai.
Durability
Sebagai contoh, misal kita buat sebuah tabel dengan nama user sebagai
berikut:
Tabel tersebut terdiri dari satu field bernama username yang bersifat unik,
yang artinya tidak boleh ada data username yang sama.
Selanjutnya, kita buat transaksi dan tambahkan data pada tabel tersebut.
Jalankan query berikut:
START TRANSACTION;
INSERT INTO user VALUES('alfa')
INSERT INTO user VALUES('bravo');
Sebagai catatan: kita juga dapat memulai transaksi dengan statemen BEGIN
atau BEGIN WORK, namun keduanya bukan standar SQL (tidak digunakan
oleh DBMS lain) sehingga disarankan menggunakan START TRANSACTION.
ROLLBACK;
Pada contoh sebelumnya, ketika kita tambahkan data pada tabel user,
MySQL belum melakukan commit, meskipun data tersebut telah
ditampilkan pada tabel user. Selanjutnya, ketika kita jalankan perintah
ROLLBACK, MySQL membatalkan semua perubahan yang telah terjadi,
sehingga tabel user menjadi kosong kembali, atau jika kita ubah ROLLBACK
menjadi COMMIT, MySQL akan melakukan commit dengan menyimpan
perubahan menjadi permanen, sehingga tabel user akan berisi data alfa
dan bravo.
mysql> ROLLBACK;
Query OK, 0 rows affected (0.04 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.09 sec)
Pada contoh diatas, meskipun kita telah menambahkan data username alfa
ke dalam tabel user, namun data tersebut belum disimpan secara
permanen. Hal tersebut dikarenakan autocommit tidak aktif, sehingga
ketika kita jalankan statemen ROLLBACK, data dikembalikan seperti semula,
jika kita jalankan statemen COMMIT, data tersebut akan disimpan secara
permanen. Hal ini mirip dengan transaksi bukan ? (ya, kita bahas di
paragraf berikutnya)
Ketika autocommit OFF, maka sejatinya Transaksi sudah berjalan baik ada
maupun tidak ada statemen START TRANSACTION, selanjutnya, ketika kita
menjalankan statemen COMMIT atau ROLLBACK, maka kita hanya membuat
apakan perubahan yang telah terjadi akan disimpan secara permanen atau
dibatalkan. Transaksi akan benar benar berhenti sampai kita mengubah
autocommit menjadi ON.
mysql> COMMIT;
Query OK, 0 rows affected (0.08 sec)
Pada query diatas, ketika kita menjalankan statemen COMMIT, maka data
akan disimpan secara permanen pada database, namun demikian,
transaksi belum berakhir, statemen setelahnya akan dianggap MySQL
sebagai bagian dari transaksi (meskipun kita tidak menjalankan kembali
statemen START TRANSACTION), mari kita lanjutkan percobaan diatas:
mysql> ROLLBACK;
Query OK, 0 rows affected (0.05 sec)
Seperti yang telah kita bahas sebelumnya, transaksi akan berakhir ketika
kita menjalankan statemen COMMIT, ROLLBACK, atau mengaktifkan kembali
autocommit. Metode tersebut merupakan metode eksplisit untuk
menghentikan transaksi, namun demikian transaksi akan otomatis
mysql> ALTER TABLE user ADD COLUMN `email` VARCHAR(50) NOT NULL
AFTER `username`;
Query OK, 0 rows affected (0.45 sec)
mysql> ROLLBACK;
Query OK, 0 rows affected (0.00 sec)
mysql> COMMIT;
Query OK, 0 rows affected (0.07 sec)
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS transaksi;
3. CREATE PROCEDURE transaksi ()
4. BEGIN
5. DECLARE sql_error BOOL DEFAULT 0;
6.
7. DECLARE EXIT HANDLER FOR SQLEXCEPTION
8. BEGIN
9. SET sql_error = 1;
10. END;
11.
12. START TRANSACTION;
13. INSERT INTO user VALUES ('nitro');
14. INSERT INTO user VALUES ('alfa'); -- Error:
duplikasi data
15. INSERT INTO user VALUES ('zebra');
16.
Jika kita jalankan, maka tidak ada penambahan data pada tabel user
karena terjadi duplikasi data pada username alfa, jika kita ganti alfa
dengan, misal gama, maka data pada tabel user akan bertambah 3
username, yaitu: nitro, gama, dan zebra
Pada query diatas, pertama tama kita definisikan variabel sql_error dengan
nilai 0, selanjutnya kita gunakan statemen DECLARE EXIT HANDLER FOR
SQLEXCEPTION untuk menangkap pesan error (ketika terjadi error). Pada
statemen tersebut, kita gunakan DECLARE EXIT karena ketika terjadi error,
maka query akan berhenti (exit), selain EXIT, terdapat handler bernama
WARNING yang akan menangkap jika ada waring). Format penulisan
DECLARE ... HANDLER adalah:
Jika statemen hanya satu baris, statemen tersebut bisa langsung ditulis
tanpa harus menggunakan BEGIN...END, sehingga statemen DECLARE pada
contoh diatas dapat kita ubah menjadi:
Untuk itu, pengujian error dapat dilakukan pada level aplikasi, sehingga
kita tidak perlu membuat stored procedure. Contoh berikut implementasi
pada PHP:
1. <?php
2. $conn = mysqli_connect('localhost', 'root', '', 'tutorial_buku');
3. if (!$conn)
4. die('Gagal terhubung dengan MySQL');
5.
6. $sql_error = 0;
7.
8. mysqli_begin_transaction($conn);
9. $query = mysqli_query($conn, "INSERT INTO user VALUES ('nitro')");
10. if (!$query)
11. $sql_error = 1;
12.
13. // ERROR: duplikasi data
14. $query = mysqli_query($conn, "INSERT INTO user VALUES ('alfa')");
15. if (!$query)
16. $sql_error = 1;
17.
18. $query = mysqli_query($conn, "INSERT INTO user VALUES ('zebra')");
19. if (!$query)
20. $sql_error = 1;
21.
22. if ($sql_error) {
23. echo 'Transaksi Gagal';
24. mysqli_rollback($conn);
25. } else {
26. echo 'Transaksi Berhasil';
27. mysqli_commit($conn);
28. }
29.
30. mysqli_close($conn);
Pada script diatas, jika query berhasil, maka PHP akan mencetak output ke
browser berupa ‘Transaksi Berhasil’ kemudian menjalankan commit,
sebaliknya, jika gagal maka PHP akan mencetak output ‘Transaksi Gagal”
dan menjalankan rollback.
Tabel: penjualan
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 2 | 3 | 2017-03-22 | 395000 |
| 3 | 2 | 2017-01-10 | 360000 |
| 4 | 1 | 2017-03-04 | 269000 |
| 5 | 4 | 2017-02-15 | 110000 |
| 6 | 3 | 2017-03-07 | 256000 |
| 7 | 2 | 2017-03-05 | 215000 |
| 8 | 3 | 2016-12-12 | 270000 |
| 9 | 3 | 2016-12-12 | 325000 |
+--------+--------------+------------+-----------+
Tabel: penjualan_detail
+---------------+--------+---------+------------+--------------+--------+-------+
| id_trx_detail | id_trx | id_buku | jml_barang | harga_satuan | diskon | total |
+---------------+--------+---------+------------+--------------+--------+-------+
| 1 | 2 | 9 | 1 | 46800 | 0 | 46800 |
| 2 | 2 | 4 | 1 | 34800 | 0 | 34800 |
| 3 | 2 | 6 | 2 | 33800 | 0 | 67600 |
| 4 | 3 | 9 | 1 | 46800 | 0 | 46800 |
| 5 | 3 | 10 | 2 | 39800 | 0 | 79600 |
+---------------+--------+---------+------------+--------------+--------+-------+
Tabel: buku
mysql> SELECT id_buku, judul, harga FROM buku WHERE id_buku IN(3,6,8);
+---------+----------------------+-------+------+
| id_buku | judul | harga | stok |
+---------+----------------------+-------+------+
| 3 | MySQL Untuk Pemula | 34800 | 5 |
| 6 | Blogger untuk Pemula | 33800 | 3 |
| 8 | Jago Wordpress | 39800 | 3 |
+---------+----------------------+-------+------+
3 rows in set (0.00 sec)
Dua buah buku MySQL Untuk Pemula dengan harga per item Rp.
34.800
Satu buah buku Blogger Untuk Pemula dengan harga per item Rp.
33.800
Satu buah buku Jago Wordpress dengan harga per item Rp. 39.800
Jika kita gunakan stored procedure, maka query untuk transaksinya adalah
sebagai berikut:
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS tambah_transaksi;
3. CREATE PROCEDURE tambah_transaksi()
4. BEGIN
5. DECLARE sql_error BOOL DEFAULT 0;
6. DECLARE id_terakhir INT;
7. DECLARE EXIT HANDLER FOR SQLEXCEPTION
8. BEGIN
9. SET sql_error = 1;
10. END;
11.
12. START TRANSACTION;
13.
14. -- Memasukkan data id_pelanggan dan tgl_trx ke penjualan
15. INSERT INTO penjualan (id_pelanggan, tgl_trx, total_trx)
16. VALUES(3, NOW(), 0);
17.
18. -- Dapatkan nilai terakhir dari id_trx
19. SET id_terakhir = LAST_INSERT_ID();
20.
21. -- Memasukkan data ke penjualan_detail
22. INSERT INTO penjualan_detail (id_trx, id_buku, jml_barang,
harga_satuan, diskon, total) VALUES
23. (id_terakhir, 3, 2, 34800, 0, 69600),
24. (id_terakhir, 6, 1, 33800, 0, 33800),
25. (id_terakhir, 8, 1, 39800, 0, 39800);
26.
27. -- Update nilai total transaksi
28. UPDATE penjualan SET total_trx = (SELECT SUM(total)
29. FROM penjualan_detail
30. WHERE id_trx = id_terakhir
31. );
32.
33. -- Update stok
34. UPDATE buku SET stok = stok - 2 WHERE id_buku = 3;
35. UPDATE buku SET stok = stok - 1 WHERE id_buku = 6;
36. UPDATE buku SET stok = stok - 1 WHERE id_buku = 8;
37.
38. IF sql_error = 0
39. THEN COMMIT;
40. ELSE
41. ROLLBACK;
42. END IF;
Untuk memastikan data yang masuk sudah benar, kita dapat cek data pada
masing masing tabel:
mysql> SELECT id_buku, judul, stok FROM buku WHERE id_buku IN(3,6,8);
+---------+----------------------+-------+
| id_buku | judul | stok |
+---------+----------------------+-------+
| 3 | MySQL Untuk Pemula | 3 |
| 6 | Blogger untuk Pemula | 2 |
| 8 | Jago Wordpress | 2 |
+---------+----------------------+-------+
3 rows in set (0.00 sec)
Dalam kondisi riil, bisa dipastikan bahwa data transaksi satu dengan yang
lain tidak akan sama, sehingga kita harus mengubah stored procedure
setiap kali ada transaksi, yaitu dengan cara menghapus ( DROP) dan
membuatnya lagi (CREATE PROCEDURE). Untuk itu, seperti yang telah kita
bahas, lebih praktis kita buat transaksi pada level aplikasi. Penerapan
transaksi diatas pada PHP:
1. <?php
2. $conn = mysqli_connect('localhost', 'root', '', 'toko_buku');
3. if (!$conn)
4. die('Gagal terhubung dengan MySQL: ' . mysqli_error($conn));
5.
Pada contoh diatas, setiap error yang terjadi kita simpan pada variabel
$sql_error, sehingga jika transaksi gagal, kita tahu query yang
menyebabkan error, sehingga mudah diperbaiki. Perhatikan pada baris 41,
kita gunakan loop untuk mengupdate data stok, cara ini lebih praktis
daripada menulis query satu per satu.
Untuk melihat storage engine yang tersedia dan fitur yang didukung, kita
dapat menggunakan perintah
SHOW ENGINES
atau
Pada tabel diatas, terlihat bahwa hanya Engine InnoDB yang mendukung
transaksi. Untuk dapat langsung memperoleh tabe yang mendukung
transaksi, kita dapat menambahkan klausa WHERE sebagai berikut:
Tabel berikut ini menggambarkan tiap level isolasi terkait dengan masalah
dirty reads, nonrepeatable reads, dan phantom rows.
Penjelasan:
Client yang memiliki privilege SUPER dapat mengatur level isolasi GLOBAL
(bentuk pertama) yang akan secara default diterapkan pada setiap client.
Namun demikian, setiap client dapat mengatur level isolasi sendiri baik
pada SESSION (bentuk kedua) atau spesifik pada transaksi tertentu
(bentuk ke tiga), tidak perlu hak akses khusus untuk mengatur level
transaksi.
transaction-isolation = REPEATABLE-READ
Misal:
Dari contoh diatas diketahui bahwa level isolasi yang digunakan adalah
REPEATABLE READ.
1. CREATE
2. TRIGGER nama_trigger
3. {BEFORE | AFTER}
4. {INSERT | UPDATE | DELETE}
5. ON nama_tabel
6. FOR EACH ROW
7. statemen
Penjelasan:
FOR EACH ROW. Artinya trigger akan dijalankan pada setiap baris yang
dikenai operasi DML. Standar ANSI menggunakan klausa FOR EACH
STATEMEN, yang hingga saat ini belum disupport oleh MySQL.
INSERT berarti trigger akan aktif jika ada data ditambahkan pada tabel,
yang biasanya dilakukan melalui statemen INSERT. Selain itu, trigger
ini juga aktif pada implisit INSERT, seperti pada statemen LOAD DATA
dan REPLACE, dimana pada kedua statemen tersebut, MySQL di
belakang layar akan menjalankan statemen INSERT
UPDATE berarti trigger akan aktif ketika ada perubahan data pada tabel
yang dilakukan melalui statemen UPDATE.
Sebagai contoh, kita akan membuat trigger dengan melibatkan tabel buku,
tabel penjualan_detail, dan tabel penjualan seperti yang kita gunakan
pada bab bab sebelumnya:
Tabel buku:
mysql> SELECT id_buku, id_kategori, judul, harga, stok FROM buku LIMIT 5;
+---------+-------------+-----------------------------------------+-------+------+
| id_buku | id_kategori | judul | harga | stok |
+---------+-------------+-----------------------------------------+-------+------+
| 1 | 3 | Pemrograman Database Menggunakan MySQL | 59000 | 5 |
| 2 | 2 | PHP dan MySQL Langkah Demi Langkah + CD | 75000 | 6 |
| 3 | 3 | MySQL Untuk Pemula | 34800 | 4 |
| 4 | 2 | Kumpulan Aplikasi PHP untuk Pemula | 34800 | 3 |
| 5 | 2 | Pemrograman PHP Dan MySQL Untuk Pemula | 69000 | 2 |
+---------+-------------+-----------------------------------------+-------+------+
5 rows in set (0.00 sec)
Tabel penjualan_detail:
Tabel penjualan:
Selanjutnya, kita akan membuat trigger yang akan mengubah data sebelum
data tersebut dimasukkan ke dalam tabel, dimana kita akan memberikan
diskon sebesar 10% untuk setiap penjualan buku dengan kategori 3,
trigger yang kita buat:
1. DELIMITER $
2. DROP TRIGGER IF EXISTS harga_diskon_bi$
3.
4. CREATE TRIGGER harga_diskon_bi
5. BEFORE INSERT ON penjualan_detail
6. FOR EACH ROW
7. BEGIN
8. DECLARE kategori INT;
9. SET kategori = (
10. SELECT id_kategori
11. FROM buku
12. WHERE id_buku = NEW.id_buku
13. );
14. IF kategori = 3 THEN
15. SET NEW.diskon = 0.1;
16. SET NEW.total = NEW.harga_satuan
17. - (NEW.harga_satuan*0.1);
18. END IF;
19. END $
20. DELIMITER ;
Selanjutnya, pada statemen IF, jika nilai kategori = 3, maka kita ubah
nilai pada kolom diskon menjadi 0.1 (10%) dan nilai pada kolom total
menjadi nilai setelah diskon.
Perintah tersebut akan mengaktifkan trigger karena pada tabel buku, buku
dengan id_buku 1 termasuk ke dalam kategori 3, maka nilai diskon dan
total akan berubah. Jika kita buka tabel penjualan_detail, maka hasil
yang kita peroleh adalah:
Pada tabel diatas terlihat bahwa meskipun kita memasukkan data diskon
0 dan total 59000, data tersebut akan diubah menjadi 0,1 (besaran diskon)
untuk diskon dan 53100 (59000 – 5900) untuk total.
Pada statemen UPDATE, keyword OLD merujuk ke data lama yang akan
diupdate, sedangkan keyword NEW merujuk data baru yang
menggantikan data lama.
Pada statemen DELETE, karena tidak ada data baru, maka hanya
digunakan keyword OLD yang merujuk ke data lama yang akan dihapus.
1. DELIMITER $
2. DROP TRIGGER IF EXISTS penjualan_detail_ai $
3.
4. CREATE TRIGGER penjualan_detail_ai
5. AFTER INSERT ON penjualan_detail
6. FOR EACH ROW
7. BEGIN
8. DECLARE total_transaksi INT;
9. SET total_transaksi = ( SELECT SUM(total)
10. FROM penjualan_detail
11. WHERE id_trx = NEW.id_trx
12. );
13.
14. UPDATE penjualan SET total_trx = total_transaksi
15. WHERE id_trx = NEW.id_trx;
16. END $
17. DELIMITER ;
Pada tabel diatas terlihat bahwa nilai total_trx berubah sesuai dengan
jumlah total penjualan dengan id_trx 7 yang ada pada tabel
penjualan_detail
1. DELIMITER $
2. DROP TRIGGER IF EXISTS penjualan_detail_au $
3.
4. CREATE TRIGGER penjualan_detail_au
5. AFTER UPDATE ON penjualan_detail
6. FOR EACH ROW
Pada query diatas kita menggunakan keyword OLD dan NEW karena jika
terjadi perubahan data pada tabel penjualan_detail, field id_trx maka
kita harus mengubah data total_trx pada tabel penjualan, baik untuk
id_trx lama (karena data berurang) dan id_trx baru (karena data
bertambah)
Misal pada data sebelumnya kita ubah data pada tabel penjualan_detail
dengan id_trx_detail 25 dari id_trx dari 7 menjadi 8
Selanjutnya mari kita cek data yang ada pada tabel penjualan:
Dari data tersebut terlihat bahwa data total_trx pada id_trx 7 dan 8 telah
berubah sesuai dengan perubahan yang ada pada tabel
penjualan_detail.
Pada query diatas, jika kita ubah data pada tabel penjualan_detail dari
id_trx 1 menjadi 2, maka data pada tabel penjualan yang memiliki id_trx
1 akan ikut terhapus, hal ini karena pada tabel penjualan_detail tidak
ada lagi data dengan id_trx 1.
Maka jika kita cek pada tabel penjualan, data dengan id_trx 1 akan hilang
Sebagai contoh, jika pada tabel penjualan_detail, kita hapus semua data
yang memiliki id_trx 7, maka data pada tabel penjualan yang memiliki
id_trx 7 menjadi tidak relevan karena detail datanya sudah tidak ada, untuk
itu, agar integritas data tetap terjaga, kita perlu membuat trigger untuk
menghapus data pada tabel penjualan tersebut.
1. DELIMITER $
2. DROP TRIGGER IF EXISTS penjualan_detail_ad $
3. CREATE TRIGGER penjualan_detail_ad
4. AFTER DELETE ON penjualan_detail
5. FOR EACH ROW
6. BEGIN
7. DECLARE jumlah_trx INT;
8. SET jumlah_trx = ( SELECT COUNT( id_trx )
9. FROM penjualan_detail
10. WHERE id_trx = OLD.id_trx
11. );
12. IF jumlah_trx = 0 THEN
13. DELETE FROM penjualan WHERE id_trx = OLD.id_trx;
14. END IF;
15. END $
16. DELIMITER ;
Selanjutnya jika kita hapus semua data dengan id_trx tertentu pada tabel
penjualan_detail, maka data pada tabel penjualan dengan id_trx yang
sama akan ikut terhapus. Contoh kita jalankan perintah:
Maka data pada tabel penjualan yang memiliki id_trx 7 juga akan ikut
terhapus.
1. DELIMITER $
2. DROP TRIGGER IF EXISTS penjualan_detail_bi $
3. CREATE TRIGGER penjualan_detail_bi
4. BEFORE INSERT ON penjualan_detail
5. FOR EACH ROW
6. BEGIN
7. DECLARE jumlah_stok INT;
8. SET jumlah_stok = ( SELECT stok
9. FROM barang
10. WHERE id_barang = NEW.id_barang
11. );
12.
13. IF jumlah_stok < NEW.jml_barang THEN
14. SIGNAL SQLSTATE '02000'
15. SET MESSAGE_TEXT = 'ERROR: Jumlah stok
tidak mencukupi';
16. END IF;
17. END
18. DELIMITER ;
Sebagai tambahan, selain ROLLBACK, pada trigger, kita juga tidak bisa
menggunakan statemen untuk memulai atau mengakhiri Stored
Procedure, yaitu: START PROCEDURE, COMMIT, atau ROLLBACK to
SAVEPOINT.
SHOW TRIGGERS
Lebih lanjut, kita juga dapat menampilkan data trigger yang ada pada tabel
tertentu. Untuk keperluan tersebut, kita gunakan klausa LIKE sebagai
berikut:
Perhatikan bahwa yang kita gunakan adalah nama tabel, bukan nama
trigger, karena sekali lagi, trigger melekat pada tabel.
Misal kita akan menampilkan data trigger yang telah kita buat sebagai
berikut:
Misal pada contoh diatas, kita tampilkan trigger yang mengandung kata
diskon, query yang kia jalankan adalah SHOW TRIGGERS WHERE `trigger`
LIKE "%diskon%"; Perlu diperhatikan bahwa kita tidak bisa
menggunakan WHERE bersama dengan LIKE.
Jika kita menghapus tabel dimana trigger tersebut berada, maka semua
trigger yang melekat pada tabel tersebut akan ikut terhapus.
Event adalah objek database yang akan dieksekusi sesuai jadwal yang telah
ditetapkan bisa sekali saja atau rutin pada periode tertentu. Event ini dapat
dianalogikan seperti aplikasi Schedule Task yang ada pada windows atau
Cron job pada UNIX. Seperti halnya event pada umumnya, pada MySQL kita
dapat membuat lebih dari satu event yang berjalan pada waktu yang
bersamaan.
Ketika statusnya non aktif maka kita tidak bisa mengubahnya menjadi ON
atau OFF, jika kita mencoba mengubahnya maka kita akan mendapati error
sebagai berikut:
Namun demikian, pada kondisi nonaktif, kita masih tetap bisa membuat,
mengubah, dan menghapus event.
Dalam satu database, tidak boleh ada event dengan nama yang sama.
Misal kita buat tabel dengan nama event_log dengan struktur sebagai
berikut:
Selanjutnya mari kita buat event dengan nama test yang akan dijalankan
pada tanggal 11 Maret 2017 pukul 19.59, waktu pembuatan event ini
adalah 11 Maret 2017 pukul 19.56
Pada event diatas, pukul 19:59 MySQL akan menambahkan data ke tabel
event_log dengan nilai test dan tanggal saat data dimasukkan.
Pada query diatas, terlebih dahulu kita kosongkan tabel event_log dan
kita hapus event test, selanjutnya kita buat event dengan nama yang sama.
Event akan dijalankan satu kali yaitu 1 menit setelah event dibuat. Event
dibuat dibuat pukul 20.17, sehingga akan dijalankan pada pukul 20.18
Contoh lain, kita buat event yang akan dijalankan 1 minggu setelah tanggal
11 Maret 2017.
Lebih jauh, mari kia buat event yang mengandung interval waktu, misal
kita buat event dengan nama test_interval yang akan dieksekusi setiap
tiga menit, sebagai berikut:
Ketika kita membuat event, terkadang nama event bentrok dengan nama
event yang sudah ada, sehingga memunculkan pesan error:
1. DELIMITER $
2. DROP EVENT IF EXISTS rekap_penjualan$
3. CREATE EVENT rekap_penjualan
4. ON SCHEDULE EVERY 1 DAY
5. STARTS '2017-03-12 00:59:55'
6. DO
7. BEGIN
8. DECLARE total_penjualan INT;
9. SET total_penjualan = (
10. SELECT SUM(total_trx)
11. FROM penjualan
12. WHERE tgl_trx = DATE(NOW())
13. );
14. INSERT INTO penjualan_rekap
15. (tgl_trx, tgl_rekap, total_trx)
16. VALUES(DATE(NOW()), NOW(),
total_penjualan);
17. END$
18. DELIMITER ;
Pada contoh diatas, event dibuat pukul 21:42 dan akan dijalankan pertama
kali pukul 21:47 (+ INTERVAL 5 MINUTE) dan selanjutnya akan dijalankan
setiap 3 menit.
Selain menentukan kapan event dieksekusi pertama kali, kita juga dapat
menentukan kapan event akan berakhir, yaitu dengan menambahkan
klausa ENDS. Misal kita buat event sebagai berikut:
Event tersebut dibuat pukul 21:56, yang berarti akan dieksekusi pertama
kali pada 3 menit berikutnya yaitu pukul 21:59, selanjutnya akan
dieksekusi setiap 1 menit dan berhenti pada pukul 22:03
Jika kita ingin event tersebut tetap ada, kita dapat lakukan dengan
menggunakan klausa ON COMPLETION yang ditulis diantara klausa ON dan
DO tetapi setelah klausa ENDS atau STARTS (jika ada). Gunakan klausa ON
COMPLETION PRESERVE agar event tersebut tidak dihapus oleh MySQL.
Nilai default adalah NOT PRESERVE, yang artinya event akan otomatis
dihapus. Misal:
Pada data diatas, terlihat bahwa status event adalah DISABLED, untuk
mengaktifkannya kembali kita harus menggunakan perintah ALTER yang
dibahas pada bagian Mengubah EVENT
Untuk membuat event tidak langsung aktif ketika dibuat, kita dapat
menggunakan klausa DISABLE yang kita tulis setelah waktu eksekusi
Selain DISABLE, kita juga dapat menggunakan klausa ENABLE yang artinya
event tersebut aktif. Klausa ini sifatnya opsional karena ketika event dibuat
statusnya langsung aktif (ENABLE). Untuk mengubah DISABLE menjadi
ENABLE kita harus menggunakan statemen ALTER
SHOW EVENTS;
Selain itu seperti pada query untuk menampilkan tabel, kita dapat
memfilter hasil yang kita inginkan menggunakan klausa WHERE, misal:
Hasil:
ALTER
EVENT event_name
[ON SCHEDULE schedule]
[ON COMPLETION [NOT] PRESERVE]
[RENAME TO new_event_name]
[ENABLE | DISABLE]
[COMMENT 'comment']
[DO event_body]
Pada syntax diatas, statemen ALTER EVENT diikuti oleh nama event,
kemudian kita pilih bagian yang ingin kita ubah, klausa yang ada di dalam
tanda kurung siku semuanya opsional. Misal kita ingin mengubah nama
event test_disabled menjadi test dan kita ubah statusnya menjadi
ENABLE
1. ALTER
2. EVENT test_disabled
3. RENAME TO test
4. ENABLE
mysql> ALTER
-> EVENT test_disabled
-> RENAME TO test
-> ENABLE;
Query OK, 0 rows affected (0.06 sec)
Mysqld error log ini secara default disimpan pada file [nama_user].err
yang ada di dalam folder data, yaitu folder tempat file database disimpan.
Nama file tersebut dapat berbeda beda tergantung konfigurasi awal ketika
kita menginstall MySQL, pada buku ini error log disimpan pada file
mysql_error.log. Contoh isi file error log terkait event:
...
2017-03-11T12:59:00.091967Z 32 [Note] Event Scheduler: Last
execution of toko_buku.test. Dropping.
2017-03-11T12:59:00.216969Z 34 [Note] Event Scheduler:
Dropping toko_buku.test
2017-03-11T13:18:11.676224Z 32 [Note] Event Scheduler: Last
execution of toko_buku.test. Dropping.
2017-03-11T13:18:11.772972Z 35 [Note] Event Scheduler:
Dropping toko_buku.test
...
2017-03-11T14:18:00.207087Z 32 [Note] Event Scheduler: Last
execution of toko_buku.test_int_1_week. Dropping.
2017-03-11T14:18:00.316435Z 36 [Note] Event Scheduler:
Dropping toko_buku.test_int_1_week
2017-03-11T15:02:38.210757Z 32 [Note] Event Scheduler: Last
execution of toko_buku.test_every_1_minute. Dropping.
2017-03-11T15:02:38.335755Z 48 [Note] Event Scheduler:
Dropping toko_buku.test_every_1_minute
2017-03-11T21:45:43.152299Z 0 [Note] InnoDB: page_cleaner:
1000ms intended loop took 23938700ms. The settings might
not be optimal. (flushed=0 and evicted=0, during the time.)
2017-03-11T22:04:30.307807Z 32 [Note] Event Scheduler: Last
execution of toko_buku.test_preserve.
Pada contoh diatas terlihat bahwa setelah event dieksekusi, event tersebut
langsung di hapus: 2017-03-12T13:18:11.676224Z 32 [Note] Event
Scheduler: Last execution of toko_buku.test. Dropping.
Semua error dan warning yang terjadi juga dicatat pada file tersebut. Misal
terjadi kesalahan ketika melakukan penulisan nama tabel yang seharusnya
event_log menjadi event_logs
Ketika kita buka file mysql_error.log, kita dapatkan pesan error sebagai
berikut:
Dari log diatas, terdapat pesan error bahwa tabel event_logs tidak ada
(Table 'toko_buku.event_logs' doesn't exist) meskipun error,
event tersebut tetap dihapus (Event Scheduler: Dropping
toko_buku.test_error)
mysql> exit;
Bye
E:\mysql-5.7.17\bin>mysqldump -u root information_schema events >
"E:\mysql-5.7.17\backup_event.sql"
Sama seperti tabel pada umumnya, metadata juga disimpan dalam bentuk
tabel, dengan demikian, untuk memperoleh data tersebut, kita juga dapat
menggunakan perintah sql seperti yang umum kita gunakan untuk
melakukan query pada tabel.
Informasi Permission.
Informasi Storage Engine.
Untuk melihat semua kolom beserta yang ada pada tabel schemata, kita
gunakan statemen yang umum kita gunakan untuk mengambil data pada
tabel:
Lanjutan tabel:
+------------------------+----------+
| DEFAULT_COLLATION_NAME | SQL_PATH |
+------------------------+----------+
| utf8_general_ci | NULL |
| latin1_swedish_ci | NULL |
| latin1_swedish_ci | NULL |
| utf8_general_ci | NULL |
| utf8_general_ci | NULL |
| latin1_swedish_ci | NULL |
| utf8_general_ci | NULL |
| latin1_swedish_ci | NULL |
+------------------------+----------+
Hasil:
+----------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+-------+
| CATALOG_NAME | varchar(512) | NO | | | |
| SCHEMA_NAME | varchar(64) | NO | | | |
| DEFAULT_CHARACTER_SET_NAME | varchar(32) | NO | | | |
| DEFAULT_COLLATION_NAME | varchar(32) | NO | | | |
| SQL_PATH | varchar(512) | YES | | NULL | |
+----------------------------+--------------+------+-----+---------+-------+
1. SELECT table_name
2. FROM information_schema.tables
3. WHERE table_schema = "toko_buku";
Hasil:
+----------------------+------------+
| table_name | table_type |
+----------------------+------------+
| buku | BASE TABLE |
| pelanggan | BASE TABLE |
| penerbit | BASE TABLE |
| pengarang | BASE TABLE |
| retur | BASE TABLE |
| diskon | BASE TABLE |
| event_log | BASE TABLE |
| kategori | BASE TABLE |
| penjualan | BASE TABLE |
| penjualan_detail | BASE TABLE |
| penjualan_rekap | BASE TABLE |
+----------------------+------------+
Misal kita akan mencari informasi tentang semua routines yang ada di
database toko_buku.
Hasil:
1. SELECT id_trx,
2. tgl_trx,
3. FROM penjualan
Terdapat struktur tabel yang tidak sesuai. Kesalahan ini terjadi ketika
MySQL berhasil mem-parse query SQL yang kita tulis, namun gagal
1. SELECT id_barang,
2. Tgl_trx
3. FROM penjualan
1. SELECT id_buku,
2. judul,
3. id_trx
4. FROM penjualan_detail,
5. LEFT JOIN buku USING (id_buku)
6. WHERE id_trx IN (SELECT id_trx
7. FROM penjualan_detail
8. GROUP BY id_trx
9. HAVING COUNT(*) > 2
10. )
Ketika kita menggunakan fungsi pada query, terkadang kita merasa bahwa
kita telah menuliskannya dengan benar, namun ternyata mendapati pesan
error, seperti contoh pada query berikut:
1. SELECT id_buku,
2. judul,
3. id_trx,
4. COUNT (id_trx) AS jml_trx
5. FROM penjualan_detail
6. LEFT JOIN buku USING (id_buku)
7. WHERE id_trx IN (SELECT id_trx
8. FROM penjualan_detail
9. GROUP BY id_buku
10. HAVING count(*) > 2
11. )
1. SELECT id_buku,
2. judul
3. FROM penjualan_detail
4. RIGHT JOIN buku
5. WHERE id_trx IS NULL
6. GROUP BY id_buku
Pada contoh error diatas, hanya ada pemberitahuan tentang error saja,
tidak diberi tahu penyebabnya apa, untuk itu, kita harus mencari sendiri.
Ketika dilakukan penelitian diketahui bahwa belum ada klausa ON atau
USING setelah JOIN.
1. SELECT bagian,
2. COUNT(
3. CASE WHEN status = "P" AND gaji = 1 AND kab = "Melawi"
4. THEN id_kar
5. END
6. ) AS hr_melawi
7. FROM data_karyawan
8. LEFT JOIN data_pekerjaan
1. SELECT id_buku,
2. judul
3. FROM penjualan_detail
4. LEFT JOIN buku USING (id_buku)
5. WHERE id_trx IN (SELECT id_trx
6. FROM penjualan_detail
7. GROUP BY id_buku
8. HAVING count(*) > 2
Pada contoh error diatas, satu satu nya petunjuk adalah line 8, sehingga
kita cari kesalahan sql di akhir line 7. Setelah diteliti, penyebab error
adalah kurang kurung tutup di bagian akhir line 7, seharusnya line 7 adalah
GROUP BY id_buku)
Fungsi yang kita gunakan pada SQL memiliki argumen dengan jumlah
tertentu, jika jumlah argumen tersebut kurang, maka akan muncul pesan
error:
1. SELECT judul,
2. LEFT (tgl_terbit, 4) AS tahun_terbit
3. FROM buku
Lagi lagi, ketika menjalankan query, pesan error yang muncul tidak secara
jelas menyebutkan kesalahan apa yang ada pada SQL, jika sudah demikian,
maka kita harus mampu mengidentifikasi sendiri, misal:
1. ( SELECT id_pelanggan,
2. tgl_trx AS tanggal,
3. 'order' AS jenis_trx
4. FROM penjualan_detail
5. LEFT JOIN penjualan USING (id_trx)
6. ORDER BY tgl_trx DESC
7. LIMIT 5
8. )
9. UNION ALL
10. SELECT id_pelanggan,
11. tgl_retur,
12. 'retur' AS jenis_trx
13. FROM retur
1. ( SELECT id_pelanggan,
2. tgl_trx AS tanggal,
3. 'order' AS jenis_trx
4. FROM penjualan_detail
5. LEFT JOIN penjualan USING (id_trx)
6. ORDER BY tgl_trx DESC
7. LIMIT 5
8. )
9. UNION ALL
10. ( SELECT id_pelanggan,
11. tgl_retur,
12. 'retur' AS jenis_trx
13. FROM retur
14. )
Catatan: error ini hanya terjadi pada MySQL versi 5.6 dan sebelumnya,
ketika menggunakan MySQL versi 5.7, query dapat berjalan dengan baik
tanpa tanda kurung pada query kedua
1. SELECT bagian,
2. COUNT(
3. CASE WHEN status = "p" AND status_gaji = 1 AND
kab = "Melawi"
4. THEN id_kar
5. END
6. ) AS hr_melawi
7. COUNT(
Error tersebut terjadi karena tidak ada koma setelah hr_melawai (baris
nomor 6), hr_melawai adalah kolom alias yang disusun dari fungsi yang
cukup kompleks. Baris 6 seharusnya seharusnya ) AS hr_melawi,
Lagi lagi pada query yang kompleks, kesalahan kecil akan cukup
merepotkan, misal ketika menjalankan query berikut:
1. DELIMITER $
2. DROP PROCEDURE IF EXISTS transaksi;
3. CREATE PROCEDURE transaksi ()
4. BEGIN
5. DECLARE sql_error BOOL DEFAULT 0;
6.
7. DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
8. BEGIN
9. SET sql_error = 1;
10. END;
11.
12. START TRANSACTION;
13. INSERT INTO user VALUES ('nitro');
14. INSERT INTO user VALUES ('alfa'); -- error: duplikasi data
15. INSERT INTO user VALUES ('zebra');
16.
17. IF sql_error = 0
18. THEN COMMIT;
19. ELSE
20. ROLLBACK;
21. END $
22. DELIMITER ;
Dalam satu query, klausa DISTINCT hanya boleh digunakan satu kali, jika
tidak, maka akan terjadi error, misal kita jalankan query:
Untuk mengatasinya, kita pilih salah satu kolom yang ingin kita terapkan
klausa distinct, misal:
Seperti yang telah kita pelajari bahwa setiap statemen pada SQL harus
diakhiri dengan delimiter, yang biasanya adalah karakter titik koma ( ; ),
pada SQL yang kompleks, terkadang kita lupa menutup statemen dengan
delimiter, misal ketika membuat trigger:
1. DELIMITER $
2. DROP TRIGGER IF EXISTS penjualan_detail_ai$
3.
4. CREATE TRIGGER penjualan_detail_ai
5. AFTER INSERT ON penjualan_detail
6. FOR EACH ROW
7. BEGIN
8. DECLARE total INT;
9. SET total = ( SELECT SUM(total)
10. FROM penjualan_detail
11. WHERE id_trx = NEW.id_trx
12. );
13.
14. UPDATE penjualan SET total_trx = total_trx
15. WHERE id_trx = NEW.id_trx
16. END $
17. DELIMITER ;
Ketika kita menjalankan query yang melibatkan beberapa tabel, maka jika
ada nama kolom yang sama, kita harus definisikan nama tabel didepannya,
jika tidak, maka akan muncul pesan error bahwa nama kolom ambigu
(ambiguous) yang artinya tidak jelas, misal kita memiliki query sebagai
berikut:
1. SELECT id_pelanggan,
2. tgl_trx,
3. tgl_retur
4. FROM penjualan
5. LEFT JOIN retur USING (id_trx)
Error tersebut terjadi karena MySQL tidak tahu harus menggunakan kolom
id_pelanggan dari tabel yang mana penjualan atau retur, untuk
mengatasi hal tersebut, kita tambahkan nama tabel pada nama kolom
id_pelanggan, misal: SELECT penjualan.id_pelanggan
1. SELECT id_pelanggan,
2. nama,
3. jml_trx,
4. total_trx
5. FROM pelanggan
Error tersebut terjadi pada bagian klausa FROM. Pada query yang
mengandung JOIN, semua tabel yang ada pada klausa join dianggap bagian
dari klausa FROM, sehingga ketika terjadi error, MySQL menyebutnya error
pada klausa FROM.
Pada query diatas, kita membuat tabel baru hasil query dari tabel
penjualan untuk digabungkan dengan tabel pelanggan, nah karena tabel
baru tersebut tidak memiliki kolom id_pelanggan, maka muncul pesan
error, jika kita pisah, bentuk tabel baru tersebut adalah:
1. SELECT id_pelanggan,
2. nama,
3. jml_trx,
4. total_trx
5. FROM pelanggan
6. LEFT JOIN (SELECT id_pelanggan, COUNT(*) AS jml_trx,
SUM(total_trx) AS total_trx
7. FROM penjualan
8. GROUP BY id_pelanggan
9. HAVING jml_trx > 1
10. ) AS penjualan
11. USING (id_pelanggan)
Hasil:
+--------------+--------------------+---------+-----------+
| id_pelanggan | nama | jml_trx | total_trx |
+--------------+--------------------+---------+-----------+
| 1 | Anton | NULL | NULL |
| 2 | Braskie | 2 | 575000 |
| 3 | Charlie | 4 | 1246000 |
| 4 | Deni | NULL | NULL |
| 5 | Erdhi | NULL | NULL |
| 6 | Ferry | NULL | NULL |
| 7 | PT. Manunggal Jaya | NULL | NULL |
| 8 | CV. Riang Gembira | NULL | NULL |
| 9 | Deni | NULL | NULL |
+--------------+--------------------+---------+-----------+
Setiap query select, kolom yang kita definisikan harus ada pada tabel yang
kita pilih, pada query yang kompleks, hal ini terkadang susah diidentifikasi,
misal kita memiliki query sebagai berikut:
Pada query diatas, kita menggabungkan tiga tabel, yaitu tabel pelanggan,
tabel penjualan (subquery), dan tabel retur. Error terjadi karena kita ingin
menampilkan data pada kolom tgl_trx, namun kolom tersebut tidak
ditemukan pada ketiga tabel tersebut. Maksud dari query diatas adalah
menampilkan tgl_trx pada tabel penjualan, untuk itu kita perlu
menambahkan kolom tersebut pada subquery:
1. ...
2. LEFT JOIN (SELECT id_pelanggan
3. COUNT(*) AS jml_trx, MAX(tgl_trx)
4. AS tgl_trx,
5. SUM(total_trx) AS total_trx
6. FROM penjualan
7. GROUP BY id_pelanggan
8. HAVING jml_trx > 1
9. ) AS penjualan
10. USING (id_pelanggan)
11. ...
Jika query yang kita jalankan mengandung subquery pada klausa FROM
baik pada klausa FROM secara langsung maupun klausa JOIN, maka
subquery tersebut akan membentuk tabel, sehingga harus diberi nama, jika
tidak, maka akan muncul pesan error. Misal, kita memiliki query:
SQL Error (1248): Every derived table must have its own
alias
... ...
8. GROUP BY id_pelanggan
9. ) AS penjualan USING (id_pelanggan)
10. LEFT JOIN retur USING (id_pelanggan)
... ...
PHP berkembang dengan cepat, banyak fitur yang ditambahkan, yang akan
dihilangkan (deprecated), dan sudah dihilangkan (removed). Pada
pembahasan kali ini, penulis menggunakan PHP versi 5.3.0, yang
membawa perubahan cukup signifikan terutama mulai dikenalkannya
ekstensi mysqli (mysql improved) dan memberikan peringatan jika masih
menggunakan ekstensi lama, yaitu mysql.
Pada file PHP, untuk membedakan kode PHP dengan kode lain, diperlukan
tag khusus sebagai pembuka dan penutup kode PHP. Setidaknya terdapat
empat tag yang dapat digunakan, namun secara default hanya dua yang
dapat digunakan, untuk menggunakan lainnya, kita harus mengubah
setting pada file php.ini
Default tag, dengan tag pembuka <?php dan tag penutup ?>, misal:
Shorthand tag
<?='Memulai PHP'?>
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. echo 'Berhasil terhubung dengan MySQL';
17. ?>
18. </body>
19. </html>
Penjelasan:
Script diatas terdiri dari script HTML dan PHP. Ketika file tersebut
dibuka melalui browser http://localhost/01_koneksi.php maka PHP
hanya akan memproses script yang ada di antara tag <?php dan ?>,
sedangkan script HTML akan dibiarkan apa adanya.
Jika koneksi gagal, maka variabel $conn akan kosong, sehingga pada
statemen if (baris 12) variabel tersebut kita uji dengan !$conn yang
artinya jika variabel $conn kosong maka telah terjadi error dan dengan
fungsi die(), kita hentikan script (PHP tidak membaca script
setelahnya).
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <p>Berhasil terhubung dengan MySQL</p>
7. </body>
8. </html>
File: 02_memilih_database.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. echo 'Berhasil terhubung dengan MySQL';
17.
18. mysqli_select_db($conn, 'toko_buku') OR
die('Database toko_buku tidak ditemukan');
19.
20. echo 'Database toko_buku berhasil dipilih';
21. ?>
22. </body>
23. </html>
Penjelasan:
File: 03_query_select.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR
die('Database toko_buku tidak ditemukan');
17.
18. $query = mysqli_query($conn, 'SELECT COUNT(*) AS
jumlah FROM pelanggan');
19. $row = mysqli_fetch_assoc($query);
20. echo $row['jumlah'];
21. ?>
22. </body>
23. </html>
1. $row = mysqli_fetch_assoc($query);
2. print_r($row);
3. /* Array
4. (
5. [jumlah] => 9
6. )*/
7.
8. $row = mysqli_fetch_array($query);
9. print_r($row);
10. /* Array
11. (
12. [0] => 9
13. [jumlah] => 9
14. )*/
15.
16. $row = mysqli_fetch_row($query);
17. print_r($row);
18. /*Array
19. (
20. [0] => 9
21. )*/
File: 04_query_select_multi.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR
die('Database toko_buku tidak ditemukan');
17.
18. $query = mysqli_query($conn, 'SELECT * FROM buku
ORDER BY tgl_terbit DESC LIMIT 5');
19.
20. if (mysqli_num_rows($query) == 0)
21. {
22. echo 'Data tidak ditemukan';
23. }
24. else
25. {
26. while ($row = mysqli_fetch_assoc($query))
27. {
28. echo 'Judul: ' . $row['judul'] . ',
29. Terbit: ' . $row['tgl_terbit'] . '<br/>';
30.
31. }
32. }
Penjelasan:
Hal ini juga berlaku untuk koneksi mysql, selama program masih
berjalan, koneksi tersebut akan terus terbuka, untuk menutupnya, kita
File: 05_query_select_tertentu.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR
die('Database toko_buku tidak ditemukan');
17.
18. $query = mysqli_query($conn, 'SELECT * FROM buku
ORDER BY tgl_terbit DESC LIMIT 5');
19.
20. mysqli_data_seek($query, 2);
21. $row = mysqli_fetch_assoc($query);
22. echo $row['judul'];
23. ?>
24. </body>
25. </html>
Penjelasan:
Pada data hasil query, kita dapat mengambil data pada baris tertentu, yaitu
menggunakan fungsi mysqli_data_seek(). Baris tersebut diurutkan
File: 06_tes_null.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR
17. die('Database toko_buku tidak ditemukan');
Hasil:
Penjelasan:
Pada query diatas, kita tes nilai pada kolom telp (baris 22), jika ada
nilainya, maka variabel $no_telp akan bernilai $row['telp'],
sedangkan jika kosong, akan bernilai 'belum ada'. Pada contoh diatas,
kita melakukan pengujian menggunakan ternary operator yang
diperpendek, yang dalam bentuk panjangnya
atau
if ($row['telp'] == '') {
$no_telp = 'belum ada';
} else {
$no_telp = $row['telp'];
Pada PHP, jika kita menggunakan tanda sama dengan sebanyak dua (
== ) maka, baik nilai NULL maupun string kosong ( "" ) akan bernilai
sama. Jika kita ingin membedakan nilai NULL dengan string kosong,
Misal pada contoh kali ini kita akan membuat Stored Procedure dengan
nama penjualan_perbulan yang berfungsi untuk menampilkan total nilai
penjualan pada suatu bulan dan banyaknya transaksi yang terjadi pada
bulan tersebut
File: 07_stored_procedure_buat.php
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
Penjelasan:
Jika kita jalankan script tersebut dua kali, maka yang kedua akan
menghasilkan output: PROCEDURE penjualan_perbulan already exists
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR
die('Database toko_buku tidak ditemukan');
17.
18. $sql = 'CALL penjualan_bulanan(3,
@total_penjualan, @jumlah_penjualan)';
19. mysqli_query($conn, $sql);
20.
21. $sql = 'SELECT @total_penjualan AS total,
@jumlah_penjualan AS jumlah';
22. $query = mysqli_query($conn, $sql);
23. $row = mysqli_fetch_assoc($query);
24. print_r($row);
25. ?>
26. </body>
27. </html>
Penjelasan:
1. <html>
2. <head>
3. <title>Koneksi MySQL</title>
4. </head>
5. <body>
6. <?php
7. $host = 'localhost';
8. $user = 'root';
9. $pass = '';
10. $conn = mysqli_connect($host, $user, $pass);
11.
12. if (!$conn) {
13. die ('Gagal terhubung dengan MySQL');
14. }
15.
16. mysqli_select_db($conn, 'toko_buku') OR die('Database
toko_buku tidak ditemukan');
17. mysqli_begin_transaction($conn);
18.
19. $sql_error = 0;
20. $query = mysqli_query($conn, 'DELETE FROM user' );
21. if (!$query)
22. $sql_error = 1;
23.
24. $query = mysqli_query($conn, 'INSERT INTO user VALUES
("sandi", "' . md5('sandi123') . '", "yola@email.com")' );
25. if (!$query)
26. $sql_error = 1;
27.
28. $query = mysqli_query($conn, 'INSERT INTO user VALUES
("zoga", "' . md5('zoga123') . '", "yola@email.com")' );
29. if (!$query)
30. $sql_error = 1;
Penjelasan:
Kolom email bersifat unik, sehingga tidak boleh ada data yang sama,
pada contoh diatas, karena pada data kedua, data email sama dengan
yang pertama, maka muncul pesan error. Karena terjadi error, maka
variabel $sql_error bernilai 1. Ketika kita tes nilai variabel tersebut
(baris 33), maka akan bernilai true, sehingga transaksi dibatalkan dan
data dikembalikan seperti semula.
Penjelasan:
Pada contoh diatas, dengan klausa LEFT JOIN, kita gabungkan data pada
tabel pelanggan yang ada pada database toko_buku dan tabel data yang
ada pada database webmap, pada penulisan tabel data, harus kita dahului
dengan menuliskan nama database yaitu webmap, karena database yang
sedang aktif adalah database toko_buku
Ben Forta, 2012. Sams Teach Yourself SQL in 10 Minutes, Fourth Edition.
USA: Sams
Larry Rockoff, 2016, The Language of SQL. USA: Pearson Education, Inc
Rick F. van der Lans, 2007. SQL for MySQL Developers: A Comprehensive
Tutorial and Reference. USA: Addison-Wesley
Timothy Boronczyk, 2015, Jump Start MySQL: Master the Database That
Powers the Web. USA: Sitepoint
URL:
http://mysql.com
http://safaribookonline.com
http://jagowebdev.com
http://www.mysqltutorial.org