KILLER TRIK
QUERY MySQL
Kupas Tuntas Teknik Olah
Data Dengan Query MySQL
SQL
Agus Prawoto Hadi
Killer Trik Query MySQL i
Killer Trik Query MySQL – Kupas
Tuntas Teknik Olah Data Dengan
Query MySQL
Penulis : Agus Prawoto Hadi
Edisi : I (Pertama)
Dimensi : 14,5 cm x 21 cm
Penulis
Statemen
Statemen adalah sebuah Query SQL utuh yang dapat dieksekusi
dengan baik.
Jika query hanya terdiri dari satu statemen, penggunaan delimiter ini
bersifat opsional, sedangkan jika query terdiri dari lebih dari satu
statemen, delimiter ini harus digunakan.
Klausa
Klausa merupakan bagian bagian tertentu dari statemen, sehingga
cakupnnya nya lebih sempit, misal klausa FROM, klausa SELECT, dst
Keyword
Keyword merupakan kata yang digunakan oleh MySQL yang
mewakili fungsi tertentu, misal COUNT, SELECT, SUM, dll. Dalam
buku ini, terkadang kita menyebut keyword dengan klausa.
iv Istilah Penting
Perbedaan ketiga istilah diatas dapat dilihat pada gambar berikut ini:
Agar syntax SQL terlihat rapi, gunakan spasi, tab, dan enter
secukupnya, sehingga dengan mudah dibedakan mana statemen,
klausa, dan keyword.
Didalam query SQL, kita bebas menggunakan spasi dan line break
dimana saja, karena ketika query tersebut dieksekusi, spasi dan line
break (enter/baris baru) akan diabaikan.
1. SELECT b.kd_barang,
2. b.nama_barang,
3. SUM(p.total_trx) AS total_pnjualan
4. FROM barang AS b
5. LEFT JOIN penjualan_detail AS pd USING(kd_barang)
6. LEFT JOIN penjualan AS p USING(id_trx)
7. WHERE YEAR(tgl_trx) = 2017
8. GROUP BY kd_barang
Khusus penulisan nama kolom pada klausa SELECT, jika nama kolom
dipisahkan dengan baris, maka ada dua cara punisan koma, yaitu (1)
koma dibelakang nama kolom, seperti pada contoh diatas, dan (2)
koma di depan nama kolom seperti contoh berikut:
vi Coding Style
1. SELECT b.kd_barang
2. , b.nama_barang
3. , SUM(p.total_trx) AS total_pnjualan
4. FROM ...
Selain file sql, juga disertakan file .php. File ini merupakan source
code script PHP yang digunakan pada pembahasan BAB 15 Table
Reporting Dengan PHP dan MySQL:. 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 tiap tiap
file .php sebelum dijalankan
Coding Style..................................................................................................................... vi
4.1. JOIN...................................................................................................................... 58
x Daftar Isi
7.1. Fungsi Scalar Pada WHERE..................................................................... 123
Pada BAB ini kita akan membahas syntax dasar statemen SELECT
beserta variasinya, dengan memahami topik ini, Anda akan dapat
dengan mudah memahami pembahasan pada bab bab berikutnya.
SELECT ...
FROM ...
[WHERE ...]
[GROUP BY ...]
[ORDER BY ...]
[HAVING ...]
[LIMIT ...]
Untuk mengambil semua kolom, kita gunakan tanda asterik (*) misal:
Hasil:
+------+---------+---------------+------------+
| nim | nama | jenis_kelamin | kd_jurusan |
+------+---------+---------------+------------+
| 001 | Alfa | L | J002 |
| 002 | Beta | P | J002 |
| 003 | Charlie | P | J001 |
| 004 | Delta | L | J001 |
| 005 | Erdhi | L | J001 |
| 006 | Farah | P | J002 |
| 007 | Gisel | P | J002 |
| 008 | Haris | L | NULL |
+------+---------+---------------+------------+
Hasil
+---------+---------------+
| nama | jenis_kelamin |
+---------+---------------+
| Alfa | L |
| Beta | P |
| Charlie | P |
| Delta | L |
| Erdhi | L |
| Farah | P |
| Gisel | P |
WHERE
Hasil:
+-------+---------------+
| nama | jenis_kelamin |
+-------+---------------+
| Alfa | L |
| Delta | L |
| Erdhi | L |
| Haris | L |
+-------+---------------+
GROUP BY
Contoh:
Sebagai contoh, jika kita jalankan query diatas, maka hasil yang kita
peroleh adalah:
+------------+-------------------+
| kd_jurusan | COUNT(kd_jurusan) |
+------------+-------------------+
| NULL | 0 |
| J001 | 2 |
| J002 | 1 |
+------------+-------------------+
Hasil:
+------------+-------------------+
| kd_jurusan | COUNT(kd_jurusan) |
+------------+-------------------+
| J002 | 1 |
| J001 | 2 |
| NULL | 0 |
+------------+-------------------+
Hasil:
+---------+---------------+
| nama | jenis_kelamin |
+---------+---------------+
| Alfa | L |
| Delta | L |
| Erdhi | L |
| Haris | L |
| Beta | P |
| Charlie | P |
| Farah | P |
| Gisel | P |
+---------+---------------+
Hasil:
+---------+---------------+
| nama | jenis_kelamin |
+---------+---------------+
| Gisel | P |
| Farah | P |
| Charlie | P |
| Beta | P |
| Haris | L |
| Erdhi | L |
| Delta | L |
| Alfa | L |
+---------+---------------+
HAVING
Hasil:
+------------+-------------------+
| kd_jurusan | COUNT(kd_jurusan) |
+------------+-------------------+
| J002 | 1 |
+------------+-------------------+
Hasil:
+------------+-------------------+
| kd_jurusan | COUNT(kd_jurusan) |
+------------+-------------------+
| J001 | 2 |
| J002 | 1 |
+------------+-------------------+
LIMIT
Hasil:
+---------+---------------+
| nama | jenis_kelamin |
+---------+---------------+
| Alfa | L |
| Beta | P |
| Charlie | P |
| Delta | L |
| Erdhi | L |
+---------+---------------+
Pada contoh diatas, data diambil 5 teratas. Secara default LIMIT akan
menghitung data mulai dari baris pertama, kita dapat menentukan
Hasil:
+-------+---------------+
| nama | jenis_kelamin |
+-------+---------------+
| Delta | L |
| Erdhi | L |
| Farah | P |
| Gisel | P |
| Haris | L |
+-------+---------------+
Kolom alias dapat ditulis dengan atau tanpa keyword AS, jika
tanpa keyword AS, pemberian nama kolom alias cukup diberi
jarak spasi, misal: qty * harga_satuan sub_total. Saya sendiri
lebih memilih menggunakan keyword AS karena mudah
diidentifikasi terutama pada query yang kompleks.
Selain sama dengan dan tidak sama dengan, kita juga dapat
menggunakan operator > (lebih besar), < (lebih kecil), >= (lebih besar
atau sama dengan), <= (lebih kecil atau sama dengan)
1. SELECT *
2. FROM mhs
3. WHERE kd_jurusan IS NULL
Hasil:
+------+-------+---------------+------------+
| nim | nama | jenis_kelamin | kd_jurusan |
+------+-------+---------------+------------+
| 008 | Haris | L | NULL |
+------+-------+---------------+------------+
Hasil:
+------------+---------------+
| kd_jurusan | jml_mahasiswa |
+------------+---------------+
| NULL | 0 |
| J001 | 2 |
| J002 | 1 |
+------------+---------------+
Hasil:
+------------+---------------+
| kd_jurusan | jml_mahasiswa |
+------------+---------------+
| J001 | 2 |
| J002 | 1 |
+------------+---------------+
Hasil:
+------------+---------+---------------+
| kd_jurusan | nama | jenis_kelamin |
+------------+---------+---------------+
| J001 | Charlie | P |
| J001 | Delta | L |
| J001 | Erdhi | L |
| NULL | Haris | L |
+------------+---------+---------------+
Pada operator AND, kondisi bernilai true, jika keduanya bernilai true,
contoh:
Hasil:
+------------+-------+---------------+
| kd_jurusan | nama | jenis_kelamin |
+------------+-------+---------------+
| J001 | Delta | L |
| J001 | Erdhi | L |
+------------+-------+---------------+
Prioritas
Ketika orator OR dan AND digunakan secara bersama sama, maka
operator AND memiliki prioritas lebih tinggi sehingga akan dievaluasi
terlebih dahulu, sehingga jika tidak hati hati, bisa jadi hasil yang kita
peroleh tidak sesuai yang kita harapkan.
Bagaimana mengatasinya?
Hasil:
Pada BAB ini akan kita membahas konsep eksekusi ini. Konsep ini
tidak mencerminkan 100% cara MySQL menangani statemen
SELECT namun akan dapat memudahkan Anda memecahkan
berbagai masalah pengambilan data.
Tabel ini bisa berupa tabel riil (Jika klausa FROM menunjuk tabel
pada database) atau tabel sementara (temporary table) – jika tabel
hasil klausa FROM tidak ada pada database, seperti penggunaan
JOIN atau subquery.
Klausa WHERE (jika ada) akan dieksekusi setelah tabel hasil klausa
FROM terbentuk, gunanya untuk membatasi jumlah data yang
diambil.
Logikanya begini…
Hal ini tentu saja sangat tidak efisien. Dengan memilih atau
membentuk tabel terlebih dahulu maka akan jauh lebih efektif ketika
memilih kolom mana yang akan diambil.
1. Untuk membuat kolom baru jika kolom tersebut belum ada pada
tabel hasil klausa FROM, misal kolom hasil perkalian atau kolom
hasil fungsi agregasi.
Ketiga…
Setelah selesai pada klausa SELECT, MySQL akan mengeksekusi
klausa opsional lain urut mulai dari GROUP BY, dst.. hingga LIMIT
Terakhir…
Setelah semua dieksekusi, MySQL akan menghasilkan tabel output
dengan kolom sesuai yang didefinisikan pada klausa SELECT
Untuk lebih memahami alur diatas, mari kita langsung praktek. Misal
kita memiiki tabel penjualan sebagai berikut:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Bagaimana querynya?
Pertama…
Ingat alur query, pertama identifikasi tabel pada klausa FROM, jika
perlu batasi data dengan klausa WHERE.
1. SELECT *
2. FROM penjualan
3. WHERE YEAR(tgl_trx) = 2017;
Hasilnya:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
+--------+--------------+------------+-----------+
Hasil diatas sudah sesuai dengan yang kita harapkan, mari kita
lanjutkan…
Kedua…
Selanjutnya kita menuju ke klausa SELECT, kita pilih kolom yang ingin
kita tampilkan, yaitu kolom id_pelanggan, tgl_trx, dan total_trx,
sehingga klausa SELECT nya menjadi:
Ketiga…
Terakhir, karena kita akan mengurutkan data berdasarkan penjualan
terbesar, maka kita gunakan klausa ORDER BY yang kita terapkan
pada pada kolom total_trx sebagai berikut:
Note: Kita akan membahas lebih jauh mengenai fungsi agregasi ini
pada bab V. Menguasai Fungsi Agregasi
Jika pada klausa SELECT terdapat fungsi agregasi –-dan pastinya kita
akan sering menggunakan fungsi ini-- maka fungsi ini akan dijalankan
belakangan bersama-sama dengan klausa GROUP BY
5. Klausa LIMIT.
Kenapa demikian?
Bingung?
Pertama…
MySQL akan mengeksekusi klausa FROM, pada kasus ini, MySQL
akan menggunakan tabel riil karena tabel penjualan_detail sudah
ada di database
Kedua…
Selanjutnya MySQL akan mengeksekusi klausa SELECT, untuk
membuat kolom baru (jika ada). Pada contoh diatas terdapat kolom
baru yaitu kolom total.
Pada tahap ini, MySQL akan membat temporary tabel yang isinya
kolom pada tabel penjualan_detai dan kolom total sebagai berikut:
+----+--------+-----------+------+--------------+--------+--------+
| id | id_trx | kd_barang | qty | harga_satuan | diskon | total |
+----+--------+-----------+------+--------------+--------+--------+
| 1 | 1 | 1 | 1 | 76000 | 0 | 76000 |
| 2 | 1 | 3 | 1 | 35000 | 0 | 35000 |
| 3 | 1 | 5 | 2 | 45000 | 0.1 | 90000 |
| 4 | 2 | 1 | 1 | 70000 | 0 | 70000 |
| 5 | 2 | 2 | 2 | 55000 | 0 | 110000 |
+----+--------+-----------+------+--------------+--------+--------+
Ketiga…
Selanjutnya, MySQL akan mengeksekusi klausa opsional yang ada,
yang yang dalam contoh kali ini klausa ORDER BY.
Catatan 1…
Kolom alias baru tersedia mulai klausa GROUP BY dst… tidak bisa
digunakan pada proses (tahapan) sebelumnya yaitu SELECT
Hasil:
+----+------+--------------+--------+
| id | qty | harga_satuan | total |
+----+------+--------------+--------+
| 5 | 2 | 55000 | 110000 |
| 3 | 2 | 45000 | 90000 |
| 1 | 1 | 76000 | 76000 |
| 4 | 1 | 70000 | 70000 |
| 2 | 1 | 35000 | 35000 |
+----+------+--------------+--------+
Pendalaman materi…
Untuk lebih memahami proses ini, misal dari contoh diatas, kita akan
mengambil data dengan total harga lebih dari 50.000
Yup. Karena klausa FROM dan WHERE akan di eksekusi pertama kali
dan pada tahap itu, hanya tersedia kolom tabel penjualan_detail dan
tidak ada kolom total
Mau tidak mau kita harus menggunakan kolom yang ada yaitu kolom
qty dan harga_satuan
Kenapa?
Pada contoh diatas, karena kolom total merupakan kolom alias dan
baru terbentuk setelah klausa GROUP BY selesai dieksekusi, maka
tidak dapat digunakan pada klausa GROUP BY
Bentuk tabel ini sangat penting karena akan menentukan tabel awal
yang akan digunakan pada tahap berikutnya, untuk itu kita perlu
meng identifikasikan bentuk tabel ini dengan benar
Pada banyak kasus, kita perlu menggunakan dua atau lebih tabel,
dan karena hasil tabel pada klausa FROM ini harus berupa satu tabel,
maka kita harus menggabungkan tabel tabel tersebut menjadi satu.
1. JOIN. Gunakan JOIN jika kolom pada tabel hasil klausa FROM
terdapat kolom dari tabel yang digabungkan, atau bisa juga jika
kedua tabel saling berhubungan (ada key antar tabel - foreign
key)
Note: Jika Anda belum memahami join, tidak masalah, cukup ikuti
saja dulu pembahasannya.
Misal kita memiliki dua buah tabel, yaitu tabel penjualan dan
pelanggan sebagai berikut:
penjualan
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
pelanggan
+--------------+---------+-----------+---------+
| id_pelanggan | nama | alamat | id_staf |
+--------------+---------+-----------+---------+
| 1 | Alfa | Jakarta | 1 |
| 2 | Beta | Semarang | 1 |
| 3 | Charlie | Surabaya | 2 |
| 4 | Delta | Surakarta | 3 |
+--------------+---------+-----------+---------+
Bagaimana querynya?
Sesuai dengan prinsip yang telah kita bahas, maka pertama kita buat
gabungan tabel melalui klausa FROM, selanjutnya kita ambil kolom
melalui klausa SELECT.
Pertama…
Karena kita menggunakan lebih dari satu tabel, maka kita perlu
identifikase tabel output…
Pada tabel output terdapat kolom nama yang berasal dari tabel
pelanggan, dan kolom tgl_trx dan total_trx yang berasal dari tabel
penjualan.
Nah karena kolom pada tabel output ada pada kedua tabel, maka
kita harus menggabungkan kedua tabel tersebut.
Jika kita perhatikan, kolom yang akan kita tampilkan adalah kolom
nama, tgl_trx, dan total_trx ketiga kolom tersebut ada pada
gabungan kedua tabel, maka tabel hasil klausa FROM harus memuat
ketiga kolom tersebut, selain itu, kedua tabel juga saling
berhubungan pada kolom id_pelanggan, oleh karena itu kita
gunakan JOIN
Hasilnya adalah:
+--------------+--------+------------+-----------+------+----------+---------+
| id_pelanggan | id_trx | tgl_trx | total_trx | nama | alamat | id_staf |
+--------------+--------+------------+-----------+------+----------+---------+
| 1 | 1 | 2017-03-02 | 192000 | Alfa | Jakarta | 1 |
| 1 | 2 | 2017-03-10 | 186000 | Alfa | Jakarta | 1 |
| 2 | 4 | 2017-04-05 | 110000 | Beta | Semarang | 1 |
| 2 | 5 | 2016-11-10 | 256000 | Beta | Semarang | 1 |
| 0 | 3 | 2017-04-10 | 259000 | NULL | NULL | NULL |
+--------------+--------+------------+-----------+------+----------+---------+
Kedua…
Selanjutnya kita definisikan kolom pada klausa SELECT, sehingga
querynya menjadi:
Hasil:
+------+------------+-----------+
| nama | tgl_trx | total_trx |
+------+------------+-----------+
| Alfa | 2017-03-02 | 192000 |
| Alfa | 2017-03-10 | 186000 |
| Beta | 2017-04-05 | 110000 |
| Beta | 2016-11-10 | 256000 |
| NULL | 2017-04-10 | 259000 |
+------+------------+-----------+
Alurnya Sama persis dengan yang telah kita bahas bada bagian
sebelumnya. Langsung saja, perhatikan ilustrasi berikut:
Pada ilustrasi diatas terlihat bahwa setiap yang kita tulis pada
statemen select (dengan pemisah tanda koma) akan selalu
menghasilkan kolom, baik nilai skalar (nilai 1) ekspresi berupa
operasi aritmatika, maupun nama kolom tabel hasil klausa FROM.
Hal ini sesuai dengan prinsip yang telah kita pelajari bahwa ketika
mengeksekusi klausa SELECT, maka jika diperlukan, MySQL akan
membuat kolom baru, nah isi dari kolom baru ini merupakan hasil
eksekusi dari setiap baris yang ada pada tabel hasil klausa FROM
Maksudnya apa?
1. WHERE;
2. GROUP BY;
3. LIMIT; dan
Namun demikian, hal ini perlu ditekankan lagi, karena pada kasus
yang rumit, kita bingung dan ragu apa yang harus dilakukan.
3. Jika ada kolom baru yang tidak ada pada tabel hasil eksekusi
klausa FROM, definisikan kolom tersebut pada klausa SELECT.
3.1. Ekspresi IF
Ekspresi logika IF berbentuk fungsi (menggunakan tanda kurung)
dan hanya dapat digunakan untuk menguji satu ekspresi.
1. if (ekspresi) {
2. ...
3. } else {
4. ...
5. }
1. if (ekspresi) {
2. ...
3. } elseif (ekspresi_lain) {
4. ...
5. }
Bagian true akan dieksekusi jika ekspresi bernilai benar dan bagian
false dieksekusi jika ekspresi bernilai salah.
Fungsi ini dapat berbentuk nested IF, yaing artinya IF didalam IF,
bentuknya seperti ini:
Kita tidak membahas lebih jauh mengenai bentuk ini karena akan
membingungkan, selain itu, lebih mudah menggunkaan ekspresi
CASE dari pada nested IF.
Demikian juga dengan fungsi IF, jika pada statemen SELECT terdapat
fungsi ini, maka fungsi ini akan dieksekusi sebanyak baris yang ada
pada tabel hasil klausa FROM
1. SELECT id_buku
2. , tgl_pinjam
3. , tgl_kembali
4. , IF(tgl_kembali = "0000-00-00", "Belum", "Sudah")
AS Kembali
5. FROM buku_pinjam
Bagaimana alurnya?
Sesuai dengan yang telah kita pelajari, pertama MySQL akan memilih
tabel sesuai yang ada pada klausa FROM yaitu tabel buku_pinjam.
1. if (ekspresi) {
2. Hasil1
3. } elseif (ekspresi2) {
1. SELECT kolom,
2. CASE
3. WHEN ekspresi1 THEN Hasil1
4. WHEN ekspresi2 THEN Hasil2
5. ...
6. [ELSE Hasil Else]
7. END
8. FROM nama_tabel
Pada query diatas, keyword CASE, WHEN, THEN, dan END wajib ada
sedangkan keyword ELSE bersifat opsional sehingga tidak wajib ada.
1. SELECT kolom,
2. CASE WHEN ekspresi THEN Hasil END
3. FROM nama_tabel
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. CASE
5. WHEN tgl_kembali = "0000-00-00" THEN "Belum Kembali"
6. ELSE CONCAT("Kembali dalam "
7. , tgl_kembali - tgl_pinjam, " Hari")
8. END AS status
9. FROM buku_pinjam
Hasil:
+---------+------------+-------------+----------------------+
| id_buku | tgl_pinjam | tgl_kembali | status |
+---------+------------+-------------+----------------------+
| 1 | 2017-05-13 | 0000-00-00 | Belum Kembali |
| 2 | 2017-05-10 | 0000-00-00 | Belum Kembali |
| 3 | 2017-05-12 | 2017-05-15 | Kembali dalam 3 Hari |
| 4 | 2017-05-14 | 0000-00-00 | Belum Kembali |
| 3 | 2017-05-12 | 2017-05-14 | Kembali dalam 2 Hari |
+---------+------------+-------------+----------------------+
Karena hanya ada satu ekspresi, maka query diatas dapat diganti
dengan fungsi IF sebagai berikut:
Contoh lebih dari satu ekspresi: kita akan menampilkan status stok
barang, misal kita memiliki tabel barang sebagai berikut:
1. SELECT nama_barang,
2. stok,
3. CASE
4. WHEN stok = 0 THEN "Habis"
5. WHEN stok > 0 AND stok < 10 THEN "Sedikit"
6. WHEN stok >= 10 AND stok < 15 THEN "Cukup"
7. ELSE "Banyak"
8. END AS status_tok
9. FROM barang
4.1. JOIN
Pada join, tabel digabungkan kemudian dihasilkan tabel baru yang
berisi data yang hanya ada pada kedua tabel.
mhs_jurusan
+------------+--------------+
| kd_jurusan | nama_jurusan |
+------------+--------------+
| J001 | MANAJEMEN |
| J002 | AKUNTANSI |
| J003 | TEKNIK |
+------------+--------------+
Hasil:
+------------+------+---------+---------------+--------------+
| kd_jurusan | nim | nama | jenis_kelamin | nama_jurusan |
+------------+------+---------+---------------+--------------+
| J002 | 001 | Alfa | L | AKUNTANSI |
| J002 | 002 | Beta | P | AKUNTANSI |
| J001 | 003 | Charlie | P | MANAJEMEN |
| J001 | 004 | Delta | L | MANAJEMEN |
| J001 | 005 | Erdhi | L | MANAJEMEN |
| J002 | 006 | Farah | P | AKUNTANSI |
| J002 | 007 | Gisel | P | AKUNTANSI |
+------------+------+---------+---------------+--------------+
Jika data pada tabel sebelah kiri tidak memiliki pasangan data
dengan tabel di sebelah kanan, maka data pada tabel sebelah kanan
akan benilai NULL
Misal kita gabungkan tabel mhs dan mhs_jurusan dengan LEFT JOIN
sebagai berikut:
1. SELECT *
2. FROM mhs
3. LEFT JOIN mhs_jurusan USING (kd_jurusan)
Mengapa demikian?
Jika data pada tabel sebelah kanan tidak memiliki pasangan dengan
tabel di sebelah kanan, maka data pada tabel sebelah kiri akan
benilai NULL
Jika kita lakukan join, baik JOIN, LEFT JOIN maupun RIGHT JOIN,
data berikut ini akan muncul
+-----------+------------+-----------+------------+------------+
| kd_barang | tgl_masuk | jml_masuk | tgl_keluar | jml_keluar |
+-----------+------------+-----------+------------+------------+
| 1 | 2017-05-02 | 14 | 2017-05-11 | 13 |
| 1 | 2017-05-03 | 5 | 2017-05-11 | 13 |
| 1 | 2017-04-26 | 7 | 2017-05-11 | 13 |
Kenapa seperti itu? Seperti yang telah kita bahas, pada join,
semua data yang ada pada kedua tabel (termasuk kombinasinya)
akan ditampilkan. Perhatikan ilustrasi berikut:
Hasil:
+-------------+-----------+------+
| nama_barang | MIN(stok) | stok |
+-------------+-----------+------+
| Mouse | 7 | 14 |
+-------------+-----------+------+
Pada contoh diatas, seharusnya stok paling kecil adalah Kabel VGA,
bukan mouse. Hal ini terjadi karena ketika menjalankan fungsi
aregasi, MySQL akan menggbungkan semua data kolom agregasi
(kolom stok) dan mengambil baris paling atas untuk kolom non
agregasi (kolom nama_barang dan stok)
Lanjutan…
Mari kita lanjutkan… berdasarkan pola diatas, untuk mencari nilai
minimal dan maksimal, kita harus menggunakan cara lain, contoh
query untuk mencari barang dengan stok terkecil:
AVG
AVG digunakan untuk mendapatkan nilai rata-rata dari suatu kolom,
misal untuk menghitung rata-rata jumlah stok, kita gunakan query
berikut:
1. SELECT AVG(stok)
2. FROM barang
Hasil:
+-----------+
| AVG(stok) |
+-----------+
| 13.0000 |
+-----------+
1. SELECT AVG(stok)
2. FROM barang
Hasil:
+-----------------------+
| ROUND( AVG(stok), 2 ) |
+-----------------------+
| 13.00 |
+-----------------------+
Hasil:
+---------+--------+
| jml_trx | total |
+---------+--------+
| 3 | 637000 |
+---------+--------+
STOP !!!
Pertama…
Seperti biasa rule pertama yang akan kita lakukan adalah
mendefinisikan bentuk tabel hasil dari klausa FROM dengan WHERE
(jika ada), untuk dapat melakukannya kita perlu untuk menganalisa
tabel output untuk menentukan tabel mana yang akan digunakan:
Pada tabel output terdapat kolom nama barang dan stok yang
kita dapatkan dari tabel barang.
Dari hasil identifikasi diatas, maka tabel hasil klausa FROM harus
melibatkan tabel barang, penjualan, dan penjualan_detail untuk itu
kita harus menggabungkan ketiganya.
Karena tabel output terdiri dari kolom yang ada pada tabel barang
dan penjualan_detail, maka kita gunakan penggabungan horizontal
yaitu menggunakan JOIN, selain itu ketiganya tabel tersebut juga
saling berhubungan
Urutan tabel dari yang pailng kiri adalah tabel barang, kenapa ? Ingat
pada pembahasan tentang LEFT JOIN, agar data ditampilkan semua,
tempatkan tabel disebelah kiri.
Karena kali ini tujuan kita menampilkan data semua barang beserta
data penjualannya, maka tujuan utama adalah menampilkan data
barang, sehingga kita letakkan tabel barang disebelah kiri.
1. SELECT *
Hasilya adalah:
+--------+-----------+-------------+------+-------+------+------+--------------+
| id_trx | id_barang | nama_barang | stok | harga | id | qty | harga_satuan |
+--------+-----------+-------------+------+-------+------+------+--------------+
| 1 | 1 | Mouse | 14 | 76000 | 1 | 1 | 76000 |
| 1 | 3 | Mousepad | 17 | 35000 | 2 | 1 | 35000 |
| 1 | 5 | Kabel VGA | 7 | 45000 | 3 | 2 | 45000 |
| 2 | 1 | Mouse | 14 | 76000 | 4 | 1 | 76000 |
| 2 | 2 | Flashdisk | 15 | 55000 | 5 | 2 | 55000 |
| 3 | 3 | Mousepad | 17 | 35000 | 6 | 2 | 35000 |
| 3 | 5 | Kabel VGA | 7 | 45000 | 7 | 1 | 45000 |
| 3 | 4 | Keyboard | 12 | 80000 | 8 | 2 | 80000 |
| 4 | 2 | Flashdisk | 15 | 55000 | 9 | 2 | 55000 |
| 5 | 4 | Keyboard | 12 | 80000 | 10 | 4 | 80000 |
+--------+-----------+-------------+------+-------+------+------+--------------+
Lanjutan...
+--------+--------------+------------+-----------+
| diskon | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 0 | 1 | 2017-02-02 | 192000 |
| 0 | 1 | 2017-02-02 | 192000 |
| 0.1 | 1 | 2017-02-02 | 192000 |
| 0 | 1 | 2017-03-10 | 186000 |
| 0 | 1 | 2017-03-10 | 186000 |
| 0 | 1 | 2017-04-10 | 259000 |
| 0 | 1 | 2017-04-10 | 259000 |
| 0.1 | 1 | 2017-04-10 | 259000 |
| 0 | 2 | 2016-12-02 | 110000 |
| 0.2 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Kedua…
Langkah selanjutnya kita susun klausa SELECT
Pada contoh kali ini kita akan menampilkan data per item barang,
sehingga data perlu dikelompokkan berdasarkan kd_barang
(GROUP BY kd_barang)
Hasil:
+-------------+------+-------------+-----------+--------+----------+
| nama_barang | stok | jml_terjual | jml_bruto | diskon | jml_neto |
+-------------+------+-------------+-----------+--------+----------+
| Mouse | 14 | 2 | 146000 | 0 | 146000 |
| Flashdisk | 15 | 2 | 110000 | 0 | 110000 |
| Mousepad | 17 | 3 | 95000 | 0 | 95000 |
| Keyboard | 12 | 2 | 160000 | 16000 | 144000 |
| Kabel VGA | 7 | 3 | 135000 | 9000 | 126000 |
+-------------+------+-------------+-----------+--------+----------+
1. SELECT
2. COUNT(
3. CASE WHEN ... THEN ...
4. END
5. )
6. FROM ...
Bagaimana Querynya?
Hasil:
+-------+----------+------------+------------+------------+------------+------------+
| tahun | id_dosen | nama_dosen | triwulan_1 | triwulan_2 | triwulan_3 | triwulan_4 |
+-------+----------+------------+------------+------------+------------+------------+
| 2016 | 2 | Bahrun | 0 | 0 | 0 | 1 |
| 2017 | 2 | Bahrun | 1 | 1 | 0 | 0 |
| NULL | 2 | Bahrun | 1 | 1 | 0 | 1 |
| 2017 | 3 | Choirul | 0 | 1 | 1 | 0 |
| NULL | 3 | Choirul | 0 | 1 | 1 | 0 |
| NULL | NULL | Choirul | 1 | 2 | 1 | 1 |
+-------+----------+------------+------------+------------+------------+------------+
Dalam praktik, kita akan sering menemui bentuk seperti ini (fungsi
agregasi digabung dengan ekspresi logika), untuk itu, kita perlu
menguasainya dengan baik, terutama alur querynya, nah, untuk itu,
pada bagian ini kita perdalam lagi bagaimana MySQL menangani
kedua fungsi tersebut secara bersamaan .
Tabel yang kita gunakan adalah tabel mhs dan mhs_status dengan
data sebagai berikut:
mhs
+------+---------+---------------+------------+
| nim | nama | jenis_kelamin | kd_jurusan |
+------+---------+---------------+------------+
| 001 | Alfa | L | J002 |
| 002 | Beta | P | J002 |
| 003 | Charlie | P | J001 |
| 004 | Delta | L | J001 |
| 005 | Erdhi | L | J001 |
| 006 | Farah | P | J002 |
| 007 | Gisel | P | J002 |
+------+---------+---------------+------------+
mhs_status
+------+-------------+
| nim | status |
+------+-------------+
| 001 | LULUS |
| 002 | TIDAK LULUS |
| 003 | TIDAK LULUS |
| 004 | LULUS |
| 005 | TIDAK LULUS |
| 006 | LULUS |
| 007 | LULUS |
+------+-------------+
Bagaimana querynya?
1. SELECT *
2. FROM mhs_status
3. LEFT JOIN mhs USING (nim);
Hasil:
+------+-------------+---------+---------------+------------+
| nim | status | nama | jenis_kelamin | kd_jurusan |
+------+-------------+---------+---------------+------------+
| 001 | LULUS | Alfa | L | J002 |
| 002 | TIDAK LULUS | Beta | P | J002 |
| 003 | TIDAK LULUS | Charlie | P | J001 |
| 004 | LULUS | Delta | L | J001 |
| 005 | TIDAK LULUS | Erdhi | L | J001 |
| 006 | LULUS | Farah | P | J002 |
| 007 | LULUS | Gisel | P | J002 |
+------+-------------+---------+---------------+------------+
Kedua…
Selanjutnya kita definisikan klausa SELECT. Pada tabel output
terdapat kolom baru yaitu L dan P, untuk itu, kita perlu
menambahkannya pada klausa SELECT
Data pada kolom tersebut berisi jenis kelamin dari mahasiswa, untuk
itu jika jenis kelamin sesuai dengan kolom, maka kita beri nilai 1 jika
Bentuk tabel hasil eksekusi klausa SELECT yang kita inginkan adalah
sebagai berikut:
+------+-------------+---------+---------------+------------+------+------+
| nim | status | nama | jenis_kelamin | kd_jurusan | L | P |
+------+-------------+---------+---------------+------------+------+------+
| 001 | LULUS | Alfa | L | J002 | 1 | NULL |
| 002 | TIDAK LULUS | Beta | P | J002 | NULL | 1 |
| 003 | TIDAK LULUS | Charlie | P | J001 | NULL | 1 |
| 004 | LULUS | Delta | L | J001 | 1 | NULL |
| 005 | TIDAK LULUS | Erdhi | L | J001 | 1 | NULL |
| 006 | LULUS | Farah | P | J002 | NULL | 1 |
| 007 | LULUS | Gisel | P | J002 | NULL | 1 |
+------+-------------+---------+---------------+------------+------+------+
1. SELECT *,
2. IF(jenis_kelamin = "L", 1, NULL) AS L,
3. IF(jenis_kelamin = "P", 1, NULL) AS P
4. FROM mhs_status
5. LEFT JOIN mhs USING (nim)
Hal ini juga berlaku ketika kita menggunakan ekspresi CASE .. WHEN
1. SELECT status,
2. COUNT(IF(jenis_kelamin = "L", 1, NULL)) AS L,
3. COUNT(IF(jenis_kelamin = "P", 1, NULL)) AS P
4. FROM mhs
5. LEFT JOIN mhs_status USING (nim)
6. GROUP BY status
Selain itu kita juga memiliki tabel guru_kota dengan data sebagai
berikut:
+---------+-------------+
| kd_kota | nama_kota |
+---------+-------------+
| 1 | Jakarta |
| 2 | Yogayakarta |
| 3 | Semarang |
| 4 | Surakarta |
+---------+-------------+
Sudah…?
Pertama…
Seperti biasa… pertama kita buat tabel pada klausa FROM, namun
sebelumnya kita perlu mengidentifikasi tabel output
Dengan bentuk output seperti diatas, maka kita perlu tabel hasil
klausa FROM sebagai berikut:
+-------------+------+------+------+------+
| nama_kota | TK | SD | SMP | SMA |
+-------------+------+------+------+------+
| Jakarta | 1 | NULL | NULL | NULL |
| Semarang | NULL | NULL | 1 | NULL |
| Yogayakarta | NULL | NULL | NULL | 1 |
| Yogayakarta | NULL | 1 | NULL | NULL |
| Surakarta | NULL | NULL | 1 | NULL |
| Jakarta | 1 | NULL | NULL | NULL |
| Semarang | NULL | NULL | NULL | 1 |
| Jakarta | NULL | 1 | NULL | NULL |
| Surakarta | NULL | 1 | NULL | NULL |
| Surakarta | NULL | NULL | 1 | NULL |
+-------------+------+------+------+------+
1. Kita akan menampilkan data nama kota, data ini ada di tabel
guru_kota, sehingga kita akan menggunakan tabel guru_kota
Selanjutnya JOIN atau LEFT JOIN? Kali ini kita gunakan LEFT JOIN dan
kita tempatkan tabel guru_kota di sebelah kiri…
Kenapa?
Karena kita akan menampilkan semua data kota yang ada di tabel
guru_kota, lihat kembali bab Menguasai JOIN
1. SELECT *
2. FROM guru_kota
3. LEFT JOIN guru USING(kd_kota)
Hasil sudah pas… kenapa? Bukankah kita perlu tabel dengan kolom
TK, SD, SMP, dan SMA? Seperti gambar V.1?
Betul…, coba perhatikan lagi adakah kolom tersebut (kolom TK, SD,
SMP, dan SMA) pada kedua tabel?
Nah karena kolom tersebut tidak ada pada tabel manapun, maka
kita perlu membuatnya, untuk membuatnya kita definisikan kolom
tersebut pada klausa SELECT, ingat, untuk menambah kolom,
gunakan klausa SELECT
Kedua…
Selanjutnya mari kita identifikasi bentuk tabel output untuk
menentukan kolom yang akan kita definisikan pada klausa SELECT
1. Nama Kota. Kolom ini sudah ada pada tabel hasil klausa FROM,
tinggal kita tulis saja
2. Kolom TK, SD, SMP, dan SMA, kolom ini tidak ada ada kedua
tabel, maka kita perlu membuatnya pada klausa SELECT
1. SELECT nama_kota
2. , COUNT(IF(mengajar = "TK", 1, NULL)) AS TK
3. , COUNT(IF(mengajar = "SD", 1, 0)) AS SD1
4. , COUNT(IF(mengajar = "SMP", 1, 0)) AS SMP
5. , COUNT(IF(mengajar = "SMA", 1, 0)) AS SMA
6. FROM guru_kota
7. LEFT JOIN guru USING(kd_kota)
8. GROUP BY kd_kota
Kenapa seperti itu? Ingat kembali tentang konsep GROUP BY, yaitu
sebelum menjalankan klausa GROUP BY, MySQL akan mengurutkan
Pengayaan….
Selanjutnya untuk melatih skill Anda, kita kembangkan tabel output
diatas sehingga muncul kolom total di sebelah kanan seperti ini:
+-------------+----+-----+-----+-----+-------+
| nama_kota | TK | SD1 | SMP | SMA | total |
+-------------+----+-----+-----+-----+-------+
| Jakarta | 2 | 3 | 3 | 3 | 11 |
| Yogayakarta | 0 | 2 | 2 | 2 | 6 |
| Semarang | 0 | 2 | 2 | 2 | 6 |
| Surakarta | 0 | 3 | 3 | 3 | 9 |
+-------------+----+-----+-----+-----+-------+
Bagaimana querynya?
1. SELECT nama_kota
2. , COUNT(IF(mengajar = "TK", 1, NULL)) AS TK
3. , COUNT(IF(mengajar = "SD", 1, 0)) AS SD
4. , COUNT(IF(mengajar = "SMP", 1, 0)) AS SMP
5. , COUNT(IF(mengajar = "SMA", 1, 0)) AS SMA
6. , COUNT(IF(mengajar = "TK", 1, NULL))
7. + COUNT(IF(mengajar = "SD", 1, 0))
8. + COUNT(IF(mengajar = "SMP", 1, 0))
9. + COUNT(IF(mengajar = "SMA", 1, 0)) AS total
10. FROM guru_kota
11. LEFT JOIN guru USING(kd_kota)
12. GROUP BY kd_kota
1. SELECT nama_kota
2. , COUNT(IF(mengajar = "TK", 1, NULL)) AS TK
3. , COUNT(IF(mengajar = "SD", 1, 0)) AS SD
4. , COUNT(IF(mengajar = "SMP", 1, 0)) AS SMP
5. , COUNT(IF(mengajar = "SMA", 1, 0)) AS SMA
Jika kita jalankan query diatas, maka akan muncul pesan error bahwa
kolom TK tidak ditemukan…
Kenapa demikian?
Karena seperti yang telah kita bahas pada bab Konsekuensi Urutan
Eksekusi, bahwa kolom tambahan dari klausa SELECT hanya dapat
digunakan pada klausa GROUP BY dst…, sehingga nama kolom pada
tabel tersebut hanya bisa digunakan pada klausa GROUP BY dst…
1. SELECT nama_kota
2. , COUNT(IF(mengajar = "TK", 1, NULL)) AS TK
3. , COUNT(IF(mengajar = "SD", 1, 0)) AS SD
4. , COUNT(IF(mengajar = "SMP", 1, 0)) AS SMP
5. , COUNT(IF(mengajar = "SMA", 1, 0)) AS SMA
6. , COUNT(IF(mengajar = "TK", 1, NULL))
7. + COUNT(IF(mengajar = "SD", 1, 0))
8. + COUNT(IF(mengajar = "SMP", 1, 0))
9. + COUNT(IF(mengajar = "SMA", 1, 0)) AS total
10. FROM guru_kota
11. LEFT JOIN guru USING(kd_kota)
12. GROUP BY kd_kota
13. ORDER BY total DESC
Contoh kita akan mengubah nama barang dari tabel barang menjadi
huruf besar semua, fungsi yang kita gunakan adalah UPPER. query
yang kita jalankan:
Hasil:
+--------------------+------+
| UPPER(nama_barang) | stok |
+--------------------+------+
| MOUSE | 14 |
| FLASHDISK | 15 |
| MOUSEPAD | 17 |
| KEYBOARD | 12 |
| KABEL VGA | 7 |
+--------------------+------+
Pada bab ini kita tidak membahas semua fungsi scalar, kita hanya
akan membahas beberapa yang penting dan sering digunakan.
Contoh:
mysql> SELECT SUBSTRING('abcde', 3, 2);
+--------------------------+
| SUBSTRING('abcde', 3, 2) |
+--------------------------+
| cd |
+--------------------------+
1 row in set (0.00 sec)
Hasil:
+------------------------------+------+
| SUBSTRING(nama_barang, 1, 4) | stok |
+------------------------------+------+
| Mous | 14 |
| Flas | 15 |
| Mous | 17 |
| Keyb | 12 |
| Kabe | 7 |
+------------------------------+------+
Contoh:
Hasil:
+----------------------+
| CONCAT('Stok: ', 14) |
+----------------------+
| Stok: 14 |
+----------------------+
Hasil:
+---------------------------------------+
| CONCAT(nama_barang, ", Stok: ", stok) |
+---------------------------------------+
| Mouse, Stok: 14 |
| Flashdisk, Stok: 15 |
| Mousepad, Stok: 17 |
| Keyboard, Stok: 12 |
| Kabel VGA, Stok: 7 |
+---------------------------------------+
Agar hasil dari fungsi tanggal dan waktu benar, maka format
tanggal (termasuk tanggal pada kolom) harus standar sesuai
yang telah kita bahas diatas.
Digit bulan dan tanggal yang dihasilkan oleh fungsi ini tidak
diawali dengan 0, seperti 1 bukan 01
1. SELECT YEAR(tgl_trx)
2. , MONTH(tgl_trx)
3. , DAY(tgl_trx)
4. , total_trx
5. FROM penjualan
DATE_FORMAT(tanggal, format_tanggal)
Format Deskripsi
Hari
%d Hari dalam satu bulan dalam dua digit (00 s.d 31)
Bulan
Tahun
Jam
Menit
Detik
Contoh:
1. SELECT tgl_trx
2. , DATE_FORMAT(tgl_trx, "%d-%m-%Y") AS tgl_trx_id
3. , total_trx
4. FROM penjualan
Hasil:
+------------+------------+-----------+
| tgl_trx | tgl_trx_id | total_trx |
+------------+------------+-----------+
| 2017-03-02 | 02-03-2017 | 192000 |
| 2017-03-10 | 10-03-2017 | 186000 |
| 2017-04-10 | 10-04-2017 | 259000 |
| 2017-04-05 | 05-04-2017 | 110000 |
| 2016-11-10 | 10-11-2016 | 256000 |
+------------+------------+-----------+
STR_TO_DATE
Fungsi STR_TO_DATE digunakan untuk mengubah format tanggal
Non-Standard SQL menjadi format tanggal standar SQL. Fungsi ini
merupakan fungsi yang penting dan sering digunakan untuk itu
harus Anda kuasai.
STR_TO_DATE(string_date, format_tanggal)
Contoh:
Hasil:
+------------+
| tanggal |
+------------+
| 2017-05-25 |
+------------+
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:
Hasil:
DATEDIFF
Fungsi DATEDIFF() digunakan untuk mencari selisih tanggal dalam
hari. Fungsi ini memiliki dua buah argumen yang wajib diisi, yaitu: (1)
tanggal akhir dan (2) tanggal awal. Format penulisannya adalah:
Contoh penggunaan:
Hasil:
1. SELECT id_buku
2. , DATEDIFF(tgl_kembali, tgl_pinjam) AS lama_pinjam
3 FROM buku_pinjam;
Hasil:
+---------+-------------+
| id_buku | lama_pinjam |
+---------+-------------+
| 1 | NULL |
| 2 | NULL |
| 3 | 3 |
| 4 | NULL |
| 3 | 2 |
+---------+-------------+
Contoh penggunaan:
Hasil:
+----------------------------------+
| TIMEDIFF("07:05:30", "07:05:01") |
+----------------------------------+
| 00:00:29 |
+----------------------------------+
Hasil:
+------------+-----------------------------------------+
| id_pegawai | TIMEDIFF(TIME(waktu_absen), "07:30:00") |
+------------+-----------------------------------------+
| 1 | -00:07:01 |
| 1 | -00:02:48 |
| 2 | -00:00:35 |
| 3 | 00:01:01 |
| 4 | 00:29:07 |
| 5 | 00:30:00 |
+------------+-----------------------------------------+
ROUND
Fungsi ROUND digunakan untuk membulatkan desimal (angka di
belakang koma). Jika angka di belakang koma bernilai 5 atau lebih,
maka akan dibulatkan ketas, jika kurang dari 5 maka akan dibulatkan
ke bawah. Adapun format penulisannya adalah:
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:
+-----------+-------+------------+--------+
| kd_barang | harga | harga_jual | diskon |
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 |
+-----------+-----------------+
Hasil:
Hasil:
+-------+--------+
| bulan | total |
+-------+--------+
| 3 | 378000 |
| 4 | 369000 |
+-------+--------+
Tabel yang akan kita gunakan adalah tabel pelanggan dan tabel
penjualan sebagai berikut:
pelanggan
+--------------+---------+-----------+---------+
| id_pelanggan | nama | alamat | id_staf |
+--------------+---------+-----------+---------+
| 1 | Alfa | Jakarta | 1 |
| 2 | Beta | Semarang | 1 |
| 3 | Charlie | Surabaya | 2 |
| 4 | Delta | Surakarta | 3 |
+--------------+---------+-----------+---------+
penjualan
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 1 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Tips: selalu gunakan konsep alur eksekusi query dan fungsi yang
telah kita pelajari…
Sudah… ?
Pertama…
Pertama selalu kita buat klausa FROM nya terlebih dahulu dan jika
perlu klausa WHERE
1. SELECT *
2. FROM penjualan
3. LEFT JOIN pelanggan USING(id_pelanggan)
4. WHERE YEAR(tgl_trx) = 2017
Hasilnya adalah:
Kedua…
2. Kolom Januari, Februari, Maret, dan April belum ada, maka kita
buat kolom tersebut. Ingat bab Kunci Menguasai SELECT, untuk
membuat kolom baru, kita definisikan kolom tersebut pada
bagian SELECT
Jika kita amati tabel hasil klausa FROM, untuk mendapatkan data
bulan, kita harus mengambil bulan pada kolom tgl_trx, maka query
yang kita perlukan adalah sebagai berikut:
1. SELECT id_pelanggan
2. , nama
3. , IF(MONTH(tgl_trx) = 1, total_trx, 0) AS Januari
4. , IF(MONTH(tgl_trx) = 2, total_trx, 0) AS Februari
Hasilnya adalah:
+--------------+------+---------+----------+--------+--------+
| id_pelanggan | nama | Januari | Februari | Maret | April |
+--------------+------+---------+----------+--------+--------+
| 1 | Alfa | 0 | 0 | 192000 | 0 |
| 1 | Alfa | 0 | 0 | 186000 | 0 |
| 2 | Beta | 0 | 0 | 0 | 110000 |
| 0 | NULL | 0 | 0 | 0 | 259000 |
+--------------+------+---------+----------+--------+--------+
Kita flash back lagi tentang fungsi IF, jika argumen paling kiri bernilai
benar, maka eksekusi argumen bagian tengah, jika salah eksekusi
argumen bagian paling kanan.
1. SELECT id_pelanggan
2. , nama
3. , SUM(IF(MONTH(tgl_trx) = 1, total_trx, 0)) AS Januari
4. , SUM(IF(MONTH(tgl_trx) = 2, total_trx, 0)) AS Februari
5. , SUM(IF(MONTH(tgl_trx) = 3, total_trx, 0)) AS Maret
6. , SUM(IF(MONTH(tgl_trx) = 4, total_trx, 0)) AS April
7. FROM penjualan
8. LEFT JOIN pelanggan USING (id_pelanggan)
9. WHERE YEAR(tgl_trx) = 2017
10. GROUP BY id_pelanggan
Hasil:
+--------------+------+---------+----------+--------+--------+
| id_pelanggan | nama | Januari | Februari | Maret | April |
+--------------+------+---------+----------+--------+--------+
| 0 | NULL | 0 | 0 | 0 | 259000 |
| 1 | Alfa | 0 | 0 | 378000 | 0 |
| 2 | Beta | 0 | 0 | 0 | 110000 |
+--------------+------+---------+----------+--------+--------+
Misal kita memiliki tabel mhs yang berisi data mahasiswa dan tabel
mhs_status yang berisi data kelulusan mahasiswa sebagai berikut:
mhs
+------+---------+---------------+------------+
| nim | nama | jenis_kelamin | kd_jurusan |
+------+---------+---------------+------------+
| 001 | Alfa | L | J002 |
| 002 | Beta | P | J002 |
| 003 | Charlie | P | J001 |
| 004 | Delta | L | J001 |
| 005 | Erdhi | L | J001 |
| 006 | Farah | P | J002 |
| 007 | Gisel | P | J002 |
+------+---------+---------------+------------+
mhs_status
+------+-------------+
| nim | status |
+------+-------------+
| 001 | LULUS |
| 002 | TIDAK LULUS |
| 003 | TIDAK LULUS |
| 004 | LULUS |
| 005 | TIDAK LULUS |
| 006 | LULUS |
| 007 | LULUS |
+------+-------------+
Seperti yang telah kita pelajari, pertama kita akan menyusun tabel
pada klausa FROM untuk diolah lebih lanjut pada klausa SELECT.
Jika kita perhatikan tabel output, maka kita perlu data jenis kelamin
dan data kelulusan, keduanya ada di dua tabel yang berbeda, maka
kita perlu menggabungkan kedua tabel tersebut.
Selanjutnya, jenis JOIN yang kita gunakan adalah LEFT JOIN dan tabel
di sebelah kiri adalah tabel mhs_status, kenapa? Karena kita ingin
menampilkan semua status
1. SELECT *
2. FROM mhs
3. LEFT JOIN mhs_status USING (nim)
Hasil:
+------+-------------+---------+---------------+------------+
| nim | status | nama | jenis_kelamin | kd_jurusan |
+------+-------------+---------+---------------+------------+
| 001 | LULUS | Alfa | L | J002 |
| 002 | TIDAK LULUS | Beta | P | J002 |
Pada tabel output, terdapat kolom baru, yaitu L dan P, kolom ini tidak
ada pada tabel hasil klausa FROM, untuk itu kita perlu membuatnya.
Bagaimana membuatnya?
Jika tabel output kita tarik mundur, kita akan memperoleh tabel
seperti ini:
+-------------+------+------+
| status | L | P |
+-------------+------+------+
| LULUS | 1 | NULL |
| TIDAK LULUS | NULL | 1 |
| TIDAK LULUS | NULL | 1 |
| LULUS | 1 | NULL |
| TIDAK LULUS | 1 | NULL |
| LULUS | NULL | 1 |
| LULUS | NULL | 1 |
+-------------+------+------+
Hasil:
+-------------+------+------+
| status | L | P |
+-------------+------+------+
| LULUS | 1 | NULL |
| TIDAK LULUS | NULL | 1 |
| TIDAK LULUS | NULL | 1 |
| LULUS | 1 | NULL |
| TIDAK LULUS | 1 | NULL |
| LULUS | NULL | 1 |
| LULUS | NULL | 1 |
+-------------+------+------+
1. SELECT status,
2. COUNT(IF(jenis_kelamin = "L", 1, NULL)) AS L,
3. COUNT(IF(jenis_kelamin = "P", 1, NULL)) AS P
4. FROM mhs
5. LEFT JOIN mhs_status USING (nim)
6. GROUP BY status
Hasil:
+-------------+---+---+
| status | L | P |
+-------------+---+---+
| LULUS | 2 | 2 |
| TIDAK LULUS | 1 | 2 |
+-------------+---+---+
Hasil:
+--------------+---+---+
| status_lulus | L | P |
+--------------+---+---+
| LULUS | 2 | 2 |
| TIDAK LULUS | 1 | 2 |
| TOTAL | 3 | 4 |
+--------------+---+---+
Sudah… ?
1. SELECT *
2. FROM barang
3. LEFT JOIN barang_masuk USING(kd_barang)
Kedua…
Selanjutnya kita definisikan kolom pada klausa SELECT. Jika
memperhatikan tabel output, maka kolom yang akan kita gunakan
adalah nama_barang dan jml_masuk (total per jenis barang) selain
itu, data yang ditampilkan hanya data bulan mei 2017
Yes, behasil..…
Yup, ternyata terdapat data barang yang hilang, yaitu kabel VGA.
Kenapa bisa begitu?
Selanjutnya, pada klausa WHERE kita beri filter tahun dan bulan pada
tgl_masuk yang mengakibatkan data tgl_masuk yang bernilai NULL
tidak masuk dalam kriteria sehingga data tersebut tidak ditampilkan.
Bagaimana mengatasinya?
Hasilnya adalah:
+-------------+-----------+
| nama_barang | jml_masuk |
+-------------+-----------+
| Mouse | 19 |
| Flashdisk | 13 |
| Mousepad | 4 |
| Keyboard | 10 |
| Kabel VGA | NULL |
+-------------+-----------+
Yes… berhasil
Sudah…?
Pertama…
Seperti prinsip yang telah kita bahas, pertama kita analisa tabel
output. Pada tabel tersebut terdapat data jumlah jenis kelamin,
status, dan jurusan, ketiganya ada di ketiga tabel, untuk itu, kita
perlu menggabungkan ketiga tabel.
Kali ini jenis penggabungan yang kita gunakan adalah LEFT JOIN dan
kita tempatkan tabel mhs di paling kiri. Mari kita tes hasil
penggabungan menggunakan statemen SELECT sebagai berikut
Sudah kan? Ya, karena kondisi pada kasus #3 ini mirip dengan kasus
#2
Kedua…
Ok, mari kita susun kolom pada klausa SELECT nya.
Masih ingat kaidah penggunaan fungsi IF ? Nah, kali ini sama seperti
kasus #2, kita perlu menguji nilai baris satu per satu apakah:
Nama jurusan manajemen dan jenis kelamin L, jika ya, beri nilai
1, jika tidak, beri nilai NULL dan letakkan pada kolom pertama
Nama jurusan manajemen dan jenis kelamin P, jika ya, beri nilai
1, jika tidak, beri nilai NULL dan letakkan pada kolom kedua
Nama jurusan akuntansi dan jenis kelamin L, jika ya, beri nilai 1,
jika tidak, beri nilai NULL dan letakkan pada kolom ketiga
Nama jurusan akuntansi dan jenis kelamin P, jika ya, beri nilai 1,
jika tidak, beri nilai NULL dan letakkan pada kolom keempat
1. SELECT status,
2. IF( jenis_kelamin = "L" AND kd_jurusan = "J001"
3. , 1, NULL) AS manajemen_l,
4. IF( jenis_kelamin = "P" AND kd_jurusan = "J001"
5. , 1, NULL) AS manajemen_p,
6. IF( jenis_kelamin = "L" AND kd_jurusan = "J002"
7. , 1, NULL) AS akuntansi_l,
8. IF( jenis_kelamin = "P" AND kd_jurusan = "J002"
9. , 1, NULL) AS akuntansi_p
10. FROM mhs_status
11. LEFT JOIN mhs USING (nim)
12. LEFT JOIN mhs_jurusan USING (kd_jurusan)
1. SELECT status,
2. COUNT(IF( jenis_kelamin = "L" AND kd_jurusan = "J001"
Query diatas sama denan studi kasus #2, bedanya kita hanya
menambahkan kondisi pada fungsi IF dengan AND jd_jurusan... dan
kita join kan tabel mhs_jurusan
Yes! berhasil
1. SELECT ...
2. FROM mhs
3. LEFT JOIN mhs_status USING (nim)
4. LEFT JOIN mhs_jurusan USING (kd_jurusan)
5. WHERE status IS NOT NULL
6. GROUP BY status
Bagaimana querynya?
Pertama…
Kita buat hubungan ketiga tabel menggunakan JOIN dan kita
tempatkan tabel mhs_jurusan di paling kiri, kenapa? Karena data
nama jurusan akan kita tampilkan semua. Selanjutnya kita tes hasil
penggabungan nya, jalankan query berikut:
1. SELECT *
2. FROM mhs_jurusan
3. LEFT JOIN mhs USING (kd_jurusan)
4. LEFT JOIN mhs_status USING (nim)
Hasil:
+------+------------+--------------+---------+---------------+-------------+
| nim | kd_jurusan | nama_jurusan | nama | jenis_kelamin | status |
+------+------------+--------------+---------+---------------+-------------+
| 001 | J002 | AKUNTANSI | Alfa | L | LULUS |
| 002 | J002 | AKUNTANSI | Beta | P | TIDAK LULUS |
| 003 | J001 | MANAJEMEN | Charlie | P | TIDAK LULUS |
| 004 | J001 | MANAJEMEN | Delta | L | LULUS |
| 005 | J001 | MANAJEMEN | Erdhi | L | TIDAK LULUS |
| 006 | J002 | AKUNTANSI | Farah | P | LULUS |
| 007 | J002 | AKUNTANSI | Gisel | P | LULUS |
| NULL | J003 | TEKNIK | NULL | NULL | NULL |
+------+------------+--------------+---------+---------------+-------------+
1. Nama Jurusan. Kolom ini sudah ada pada tabel hasil klausa
FROM, sehingga tinggal kita tuliskan pada klausa SELECT
4. Tidak Lulus. Kolom ini juga belum ada, sehingga kita perlu
membuatnya. Nilai kolom ini kita ambil dari banyaknya nim
dengan status tidak lulus
Dari hasil analisa diatas, susunan kolom pada klausa SELECT adalah
sebagai berikut:
Hasil:
+--------------+------------------+-------+-------------+
| Nama Jurusan | Jumlah Mahasiswa | Lulus | Tidak Lulus |
+--------------+------------------+-------+-------------+
Hasil:
+--------------+------------------+-------+-------------+
| Nama Jurusan | Jumlah Mahasiswa | Lulus | Tidak Lulus |
+--------------+------------------+-------+-------------+
| MANAJEMEN | 3 | 1 | 2 |
| AKUNTANSI | 4 | 3 | 1 |
| TEKNIK | 0 | 0 | 0 |
+--------------+------------------+-------+-------------+
Pengayaan….
Selanjutnya, untuk lebih mengasah kemampuan Anda, silakan
kembangkan tabel diatas dengan menambahkan kolom persentase
sebagai berikut:
+--------------+------------------+-------+---------+-------------+---------------+
| Nama Jurusan | Jumlah Mahasiswa | Lulus | % Lulus | Tidak Lulus | % Tidak Lulus |
+--------------+------------------+-------+---------+-------------+---------------+
| MANAJEMEN | 3 | 1 | 33.33% | 2 | 66.67% |
| AKUNTANSI | 4 | 3 | 75.00% | 1 | 25.00% |
| TEKNIK | 0 | 0 | NULL | 0 | NULL |
+--------------+------------------+-------+---------+-------------+---------------+
Ayo dicoba…
Sudah bisa.. ?
Silakan Anda coba ya.. sudah banyak contoh seperti ini pada latihan
sebelumnya… practice make perfect…. Benar?
Sudah bisa?
Pertama…
Seperti biasa, pertama kita analisa tabel yang diperlukan dengan
melihat output tabel.
Pada output tabel, kita akan menghitung data guru yang ada pada
tabel sekolah_guru dengan mengelompokkannya per kabupaten
(tabel sekolah_kab), berdasarkan hubungan gambar diatas, maka
mau tidak mau kita harus melibatkan keempat tabel, karena agar
tabel sekolah_kab dapat terhubung dengan sekolah_guru, kita harus
melibatkan tabel sekolah dan sekolah_kec
Sudah benar?
Kenapa begitu?
Hasil:
+-------------+-----------+---------+-----------+
| nama_kab | nama_guru | jenjang | pelatihan |
+-------------+-----------+---------+-----------+
| Kabupaten 3 | Aldi | SD | IKUT |
| Kabupaten 1 | Budi | SD | |
| Kabupaten 3 | Cyndi | SMP | IKUT |
| Kabupaten 2 | Denny | SMP | IKUT |
| Kabupaten 1 | Erdi | SD | IKUT |
| Kabupaten 2 | Ferry | SMA | IKUT |
| Kabupaten 2 | Gari | SMA | IKUT |
| Kabupaten 1 | Hari | SD | |
| Kabupaten 1 | Indri | SMP | IKUT |
| Kabupaten 1 | Jeni | SMP | IKUT |
| Kabupaten 4 | NULL | NULL | NULL |
+-------------+-----------+---------+-----------+
Kedua…
Kedua mari kita susun kolom pada klausa SELECT. Bagian Kolom
Nama kabupaten sudah tersedia, kita tinggal menuliskannya pada
klausa SELECT, untuk kolom SD, SMP, SMA, dan TOTAL, kita perlu
membuatnya. Jalankan query berikut:
Hasil:
+----------------+------+------+------+-------+
| Nama Kabupaten | SD | SMP | SMA | TOTAL |
+----------------+------+------+------+-------+
| Kabupaten 3 | 1 | NULL | NULL | 1 |
| Kabupaten 1 | NULL | NULL | NULL | NULL |
| Kabupaten 3 | NULL | 1 | NULL | 1 |
| Kabupaten 2 | NULL | 1 | NULL | 1 |
| Kabupaten 1 | 1 | NULL | NULL | 1 |
| Kabupaten 2 | NULL | NULL | 1 | 1 |
| Kabupaten 2 | NULL | NULL | 1 | 1 |
| Kabupaten 1 | NULL | NULL | NULL | NULL |
| Kabupaten 1 | NULL | 1 | NULL | 1 |
| Kabupaten 1 | NULL | 1 | NULL | 1 |
| Kabupaten 4 | NULL | NULL | NULL | NULL |
+----------------+------+------+------+-------+
Selanjutnya kita hitung jumlah baris untuk kolom SD, SMP, dan SMA
menggunakan fungsi COUNT. Jangan lupa karena kita akan
mengelompokkan data berdasarkan nama kabupaten, maka kita
tambahkan klausa GROUP BY kd_kab
Hasil:
Cara lain…
Query adalah seni sehingga banyak jalan untuk memecahkan kasus,
demikian juga dengan kasus diatas, kasus diatas juga dapat di
selesaikan menggunakan query berikut:
1. SELECT nama_partai,
2. COUNT(nama_anggota) AS jumlah_anggota,
3. periode
4. FROM anggota_dewan
5. GROUP BY nama_partai, periode
6. ORDER BY periode
Hasil:
+-------------+----------------+-----------+
| nama_partai | jumlah_anggota | periode |
+-------------+----------------+-----------+
| Rakyat | 3 | 2010-2015 |
| PRDD | 1 | 2010-2015 |
| Rakyat | 1 | 2015-2020 |
| PRDD | 2 | 2015-2020 |
+-------------+----------------+-----------+
1. SELECT nama_partai,
2. COUNT(nama_partai) AS jumlah,
3. ROUND( COUNT(nama_partai)
4. / (SELECT COUNT(*)
5. FROM anggota_dewan
6. WHERE periode = t1.periode) * 100, 2
Hasil:
+-------------+--------+--------+-----------+
| nama_partai | jumlah | persen | periode |
+-------------+--------+--------+-----------+
| Rakyat | 3 | 75.00 | 2010-2015 |
| PRDD | 1 | 25.00 | 2010-2015 |
| Rakyat | 1 | 33.33 | 2015-2020 |
| PRDD | 2 | 66.67 | 2015-2020 |
+-------------+--------+--------+-----------+
Pada query diatas, klausa SELECT akan dieksekusi pada setiap baris
tabel anggota_dewan sehingga klausa WHERE periode = t1.periode
pada subquery akan berubah ubah sesuai dengan baris yang ada,
misal pada baris pertama, klausa where menjadi WHERE periode =
2010-2015, sedangkan pada baris ke 3 WHERE periode = 2015-2020
Untuk memahami model subquery ini, mari kita belajar dari contoh
kasus.
Pertama…
Kita identifikasi data yang ingin ditampilkan, yaitu kd_barang,
nama_barang, dan jml_masuk, dan jml_keluar. Ketiganya ada di tabel
barang, barang_masuk, dan barang_keluar, untuk itu kita perlu
menggabungkan ketiga tabel.
1. SELECT *
2. FROM barang
3. LEFT JOIN barang_masuk USING(kd_barang)
4. LEFT JOIN barang_keluar USING(kd_barang)
Ternyata tabel yang dihasilkan terdiri dari banyak sekali row, hal ini
seperti yang telah kita bahas pada bagian JOIN, bahwa ketika kita
menggabungkan tabel, maka semua kombinasi dari data yang
berhubungan akan ditampilkan semua.
Kedua…
Setelah memiliki gambaran tabel hasil penggabungan, maka
selanjutnya kita susun kolom pada klausa SELECT, selain itu kita
tambahkan klausa WHERE untuk memfilter data sehingga hanya
diambil data bulan Mei 2017. Oiya jangan lupa menambahkan klausa
GROUP BY karena kita akan menjumlahkan data per barang.
1. SELECT kd_barang
2. , nama_barang
3. , SUM(jml_masuk) AS jml_masuk
4. , SUM(jml_keluar) AS jml_keluar
5. FROM barang
6. LEFT JOIN barang_masuk USING (kd_barang)
7. LEFT JOIN barang_keluar USING (kd_barang)
8. WHERE (YEAR(tgl_masuk) = 2017 AND YEAR(tgl_masuk) = 2017
9. AND MONTH(tgl_masuk) = 5 AND MONTH(tgl_masuk) = 5)
10. OR tgl_masuk IS NULL OR tgl_keluar IS NULL
11. GROUP BY kd_barang
Ternyata hasil yang kita peroleh berbeda. Kenapa seperti itu? Coba
perhatikan tabel hasil penggabungan, data baik pada kolom
jml_masuk maupun kolom jml_keluar, datanya dobel sehingga ketika
dijumlahkan menggunakan SUM, jumlahnya menjadi lebih besar.
Bagaimana mengatasinya?
Pertama…
Pertama kita susun ulang hubungan antar tabel, kita terjemahkan
gambar diatas menjadi bentuk query, hasilnya adalah sebagai
berikut:
1. SELECT *
2. FROM barang
3. LEFT JOIN
4. ( SELECT kd_barang, SUM(jml_masuk) AS jml_masuk
5. FROM barang_masuk
6. WHERE MONTH(tgl_masuk) = 5 AND YEAR(tgl_masuk) = 2017
7. GROUP BY kd_barang
8. ) AS barang_masuk USING(kd_barang)
9. LEFT JOIN
10. (
11. SELECT kd_barang, SUM(jml_keluar) AS jml_keluar
12. FROM barang_keluar
13. WHERE MONTH(tgl_keluar) = 5 AND YEAR(tgl_keluar) = 2017
14. GROUP BY kd_barang
15. ) AS brg_keluar USING(kd_barang)
Hasil diatas sudah mendekati apa yang kita harapkan, tinggal kita
pilih kolom yang ingin ditampilkan melalui klausa SELECT
Mungkin anda bertanya tanya, dimana letak tabel hasil subquery ini?
Tabel hasil subquery disimpan di dalam memory (RAM) dan akan
dihapus setelah eksekusi query selesai, oleh karena itu, tabel ini
dinamakan temporary table (tabel sementara). Karena disimpan
pada memory maka semakin besar tabel hasil subquery ini, maka
semakin besar space memory yang digunakan.
Untuk lebih memahami perbedaan UNION dan UNION ALL, misal kita
memiliki tabel kredit_agen dan kredit_survey, dan kredit_closing
sebagai berikut:
kredit_agen
+----+--------------+------------+---------+
| id | nama_pegawai | tanggal | nasabah |
+----+--------------+------------+---------+
| 1 | Alfa | 2017-06-10 | Toni |
| 2 | Beta | 2017-06-11 | Sapta |
| 3 | Charlie | 2017-06-12 | Umar |
| 4 | Beta | 2017-06-13 | Versa |
+----+--------------+------------+---------+
kredit_survey
+----+--------------+------------+---------+
| id | nama_pegawai | tanggal | nasabah |
+----+--------------+------------+---------+
| 1 | Beta | 2017-06-17 | Toni |
| 2 | Charlie | 2017-06-18 | Sapta |
| 3 | Ekky | 2017-06-19 | Umar |
| 4 | Charlie | 2017-06-20 | Versa |
+----+--------------+------------+---------+
kredit_closing
+----+--------------+------------+---------+
| id | nama_pegawai | tanggal | nasabah |
1. SELECT nama_pegawai
2. FROM kredit_agen
3. UNION
4. SELECT nama_pegawai
5. FROM kredit_survey
6. UNION
7. SELECT nama_pegawai
8. FROM kredit_closing
Dari hasil diatas terlihat tidak ada nama yang muncul lebih dari
sekali, jika kita gunakan UNION ALL, maka nama Charlie akan
muncul empat kali
Selanjutnya kita gabungkan semua data pada ketiga tabel dan kita
beri tanda, mana yang calling, survey, dan closing, jalankan query
berikut:
Hasil:
+--------------+---------+
| nama_pegawai | jenis |
+--------------+---------+
| Alfa | calling |
| Beta | calling |
| Charlie | calling |
| Beta | calling |
| Alfa | calling |
| Beta | survey |
| Charlie | survey |
| Ekky | survey |
| Charlie | survey |
| Charlie | closing |
| Ferry | closing |
| Alfa | closing |
| Ferry | closing |
+--------------+---------+
Latihan…
Sebagai latihan, coba Anda tampilkan data pegawai beserta jumlah
calling, survey, dan closing nya, tabel output yang kita inginkan
seperti berikut ini:
+--------------+---------+--------+---------+
| nama_pegawai | calling | survey | closing |
+--------------+---------+--------+---------+
| Alfa | 2 | 0 | 1 |
Sudah bisa…?
Pertama…
Kita identifikasi bentuk tabel hasil klausa FROM, namun sebelumnya,
karena melibatkan lebih dari satu tabel, kita analisa terlebih dahulu
tabel outputnya.
Dari hasil analisa tabel output, kita membutuhkan data ketiga tabel,
sehingga kita perlu menggabungkan ketiga tabel tersebut menjadi
satu.
1. SELECT *
2. FROM kredit_calling
3. UNION ALL
4. SELECT *
5. FROM kredit_survey
6. UNION ALL
7. SELECT *
8. FROM kredit_closing
Hasil:
+----+--------------+------------+---------+
| id | nama_pegawai | tanggal | nasabah |
+----+--------------+------------+---------+
| 1 | Alfa | 2017-06-10 | Toni |
| 2 | Beta | 2017-06-11 | Sapta |
| 3 | Charlie | 2017-06-12 | Umar |
| 4 | Beta | 2017-06-13 | Versa |
| 5 | Alfa | 2017-06-14 | Zeti |
| 1 | Beta | 2017-06-17 | Toni |
| 2 | Charlie | 2017-06-18 | Sapta |
| 3 | Ekky | 2017-06-19 | Umar |
| 4 | Charlie | 2017-06-20 | Versa |
| 1 | Charlie | 2017-06-17 | Toni |
| 2 | Ferry | 2017-06-18 | Sapta |
| 3 | Alfa | 2017-06-19 | Umar |
| 4 | Ferry | 2017-06-20 | Versa |
+----+--------------+------------+---------+
Tapi tunggu…
Ternyata tidak bisa, untuk itu, kita perlu membuat data baru
sehingga dapat dibedakan mana tabel calling, tabel survey, dan tabel
closing, salah satunya adalah sebagai berikut:
+--------------+---------+
| nama_pegawai | jenis |
+--------------+---------+
| Alfa | calling |
| Beta | calling |
| Charlie | calling |
| Beta | calling |
| Alfa | calling |
| Beta | survey |
| Charlie | survey |
| Ekky | survey |
| Charlie | survey |
| Charlie | closing |
| Ferry | closing |
| Alfa | closing |
| Ferry | closing |
+--------------+---------+
Kolom jenis pada tabel diatas digunakan untuk pembeda tabel, Anda
bebas menggantinya dengan bentuk lain.
Dengan query diatas, bentuk tabel hasil klausa FROM akan seperti
berikut ini:
+--------------+---------+
| nama_pegawai | jenis |
+--------------+---------+
| Alfa | calling |
| Beta | calling |
| Charlie | calling |
| Beta | calling |
| Alfa | calling |
| Beta | survey |
| Charlie | survey |
| Ekky | survey |
| Charlie | survey |
| Charlie | closing |
| Ferry | closing |
| Alfa | closing |
| Ferry | closing |
+--------------+---------+
Kedua…
Seperti biasa, setelah mendapatkan gambaran tabel hasil klausa
FROM, selanjutnya kita susun kolom pada klausa SELECT
Karena kita perlu kolom baru, yaitu kolom calling, survey, dan closing,
maka kita perlu mendefinisikan kolom tersebut pada klausa SELECT
dengan query sebagai berikut:
1. SELECT nama_pegawai
2. , IF(jenis="calling", 1, NULL) AS calling
3. , IF(jenis="survey", 1, NULL) AS survey
Hasil:
+--------------+---------+--------+---------+
| nama_pegawai | calling | survey | closing |
+--------------+---------+--------+---------+
| Alfa | 1 | NULL | NULL |
| Beta | 1 | NULL | NULL |
| Charlie | 1 | NULL | NULL |
| Beta | 1 | NULL | NULL |
| Alfa | 1 | NULL | NULL |
| Beta | NULL | 1 | NULL |
| Charlie | NULL | 1 | NULL |
| Ekky | NULL | 1 | NULL |
| Charlie | NULL | 1 | NULL |
| Charlie | NULL | NULL | 1 |
| Ferry | NULL | NULL | 1 |
| Alfa | NULL | NULL | 1 |
| Ferry | NULL | NULL | 1 |
+--------------+---------+--------+---------+
1. SELECT nama_pegawai
2. , COUNT(IF(jenis="calling", 1, NULL)) AS calling
3. , COUNT(IF(jenis="survey", 1, NULL)) AS survey
4. , COUNT(IF(jenis="closing", 1, NULL)) AS closing
5. FROM
6. (
7. SELECT nama_pegawai, "calling" AS jenis
8. FROM kredit_calling
9. UNION ALL
10. SELECT nama_pegawai, "survey" AS jenis
11. FROM kredit_survey
Hasil:
+--------------+---------+--------+---------+
| nama_pegawai | calling | survey | closing |
+--------------+---------+--------+---------+
| Alfa | 2 | 0 | 1 |
| Beta | 2 | 1 | 0 |
| Charlie | 1 | 2 | 1 |
| Ekky | 0 | 1 | 0 |
| Ferry | 0 | 0 | 2 |
+--------------+---------+--------+---------+
Selanjutnya coba Anda buat baris total untuk baris dan kolom
sebagai berikut:
+--------------+---------+--------+---------+-------+
| nama_pegawai | calling | survey | closing | total |
+--------------+---------+--------+---------+-------+
| Alfa | 2 | 0 | 1 | 3 |
| Beta | 2 | 1 | 0 | 3 |
| Charlie | 1 | 2 | 1 | 4 |
| Ekky | 0 | 1 | 0 | 1 |
| Ferry | 0 | 0 | 2 | 2 |
| TOTAL | 5 | 4 | 4 | 13 |
+--------------+---------+--------+---------+-------+
Total
Contoh pertama kita akan membuat baris total yang ada di bagian
paling bawah, misal kita memiliki tabel penjualan sebagai berikut:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Hasil:
+--------+------------+-----------+
| id_trx | tgl_trx | total_trx |
+--------+------------+-----------+
| 1 | 2017-03-02 | 192000 |
Pada contoh diatas terlihat sebuah baris baru yang berisi total nilai
kolom total_trx
Sub Total
Selain baris total, dalam praktik kita juga sering membuat baris sub
total, pada subtotal, data dikelompokkan berdasarkan kriteria
tertentu.
Bagaimana querynya?
Sebagai clue (petunjuk), kali ini kita akan menggunakan dua buah
tabel yaitu tabel penjualan dan pelanggan sebagai berikut:
penjualan
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
pelanggan
Silakan dicoba….
Sudah bisa?
Pertama…
Seperti biasa kita susun klausa FROM, karena melibatkan dua tabel,
kita harus menggunakan JOIN, pilihannya JOIN atau LEFT JOIN.
Caranya, kita gunakan UNION dan ORDER BY. Pertama kita buat total
per id_pelanggan.
Hasilnya adalah:
+-----------+--------------+-----------+------------+-----------+
| id_trx | id_pelanggan | nama | tgl_trx | total_trx |
+-----------+--------------+-----------+------------+-----------+
| 1 | 1 | Alfa | 2017-03-02 | 192000 |
| 2 | 1 | Alfa | 2017-03-10 | 186000 |
| 4 | 2 | Beta | 2017-04-05 | 110000 |
| 5 | 2 | Beta | 2016-11-10 | 256000 |
| 3 | 0 | NULL | 2017-04-10 | 259000 |
| SUB TOTAL | 0 | SUB TOTAL | | 259000 |
| SUB TOTAL | 1 | SUB TOTAL | | 378000 |
| SUB TOTAL | 2 | SUB TOTAL | | 366000 |
+-----------+--------------+-----------+------------+-----------+
Selain itu kita juga akan menambahkan baris total pada bagian akhir
tabel, sehingga hasil akhir tabel adalah sebagai berikut:
+----------------+-------------------+-----------------+
| Nama Pelanggan | Tanggal Transaksi | Nilai Transaksi |
+----------------+-------------------+-----------------+
| - | 2017-04-10 | 259000 |
| SUB TOTAL | | 259000 |
| Alfa | 2017-03-02 | 192000 |
| Alfa | 2017-03-10 | 186000 |
| SUB TOTAL | | 378000 |
| Beta | 2017-04-05 | 110000 |
| Beta | 2016-11-10 | 256000 |
| SUB TOTAL | | 366000 |
| TOTAL | | 1003000 |
+----------------+-------------------+-----------------+
Hasilnya adalah:
+----------------+-------------------+-----------------+
| Nama Pelanggan | Tanggal Transaksi | Nilai Transaksi |
+----------------+-------------------+-----------------+
| - | 2017-04-10 | 259000 |
| SUB TOTAL | | 259000 |
| Alfa | 2017-03-02 | 192000 |
| Alfa | 2017-03-10 | 186000 |
| SUB TOTAL | | 378000 |
| Beta | 2017-04-05 | 110000 |
| Beta | 2016-11-10 | 256000 |
| SUB TOTAL | | 366000 |
+----------------+-------------------+-----------------+
Hal ini tidak kita lakukan karena kedua kolom itu kita gunakan untuk
mengurutkan data, lihat klausa ORDER BY
Kembali ke tabel hasil query… hasilnya sudah mirip dengan yang kita
inginkan bukan? Nah selanjutnya tinggal kita tambahkan baris total.
Bisa?
Baiklah, mari kita cocokkan. Query merurut versi saya adalah sebagai
berikut:
Hasil:
+----------------+-------------------+-----------------+
| Nama Pelanggan | Tanggal Transaksi | Nilai Transaksi |
+----------------+-------------------+-----------------+
| - | 2017-04-10 | 259000 |
Equivalen / Alternatif
Seribu jalan menuju Roma, banyak cara memecahkan masalah.
Demikian juga dengan query total dan sub total diatas, kita dapat
menggunakan cara lain untuk menghasilkan tabel yang sama persis.
Namun jika Anda penasaran ingin segera tahu querynya seperti apa,
berikut ini query jadinya:
1. SELECT CASE
2. WHEN id_trx IS NULL AND id_pelanggan IS NOT NULL
3. THEN "SUB TOTAL"
4. WHEN id_trx IS NULL AND id_pelanggan IS NULL
5. THEN "TOTAL"
6. WHEN nama IS NULL
7. THEN "-"
8. ELSE nama
9. END AS Nama
10. , IF(ISNULL(id_trx), "", tgl_trx) AS "Tanggal Transaksi"
11. , total_trx AS "Total Transaksi"
12. FROM
13. (
14. SELECT id_trx, id_pelanggan
Hasilnya:
+----------------+-------------------+-----------------+
| Nama Pelanggan | Tanggal Transaksi | Nilai Transaksi |
+----------------+-------------------+-----------------+
| - | 2017-04-10 | 259000 |
| SUB TOTAL | | 259000 |
| Alfa | 2017-03-02 | 192000 |
| Alfa | 2017-03-10 | 186000 |
| SUB TOTAL | | 378000 |
| Beta | 2017-04-05 | 110000 |
| Beta | 2016-11-10 | 256000 |
| SUB TOTAL | | 366000 |
| TOTAL | | 1003000 |
+----------------+-------------------+-----------------+
Nah, studi kasus kali ini kita akan membahas bagaimana cara
melakukan itu, kita gunakan contoh pada pembahasan pembuatan
baris total, mari kita lihat kembali querynya:
Hasil:
+--------+------------+-----------+
| id_trx | tgl_trx | total_trx |
+--------+------------+-----------+
| 1 | 2017-03-02 | 192000 |
| 2 | 2017-03-10 | 186000 |
| 3 | 2017-04-10 | 259000 |
| 4 | 2017-04-05 | 110000 |
| 5 | 2016-11-10 | 256000 |
| TOTAL | | 1003000 |
+--------+------------+-----------+
1. SELECT *
2. FROM
3. ( SELECT IFNULL(nama, "-") AS nama, tgl_trx, total_trx
4. FROM penjualan
5. LEFT JOIN pelanggan USING (id_pelanggan)
6. ORDER BY total_trx DESC
7. ) AS penjualan_rinci
8. UNION ALL
9. SELECT 'TOTAL',"", SUM(total_trx)
10. FROM penjualan
Query tersebut dapat berjalan dengan baik, namun data pada query
pertama tidak berubah, kenapa? Karena seperti pada konsep
UNION, MySQL tidak memproses klausa setelah GROUP BY yang ada
pada pada masing masing klausa SELECT yang dilakukan secara
langsung (tanpa subquery).
Untuk lebih jelasnya, misal kita miliki tabel penjualan dengan data
sebagai berikut:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Hasil:
+--------+--------------+------------+----------------+
| id_trx | id_pelanggan | tgl_trx | SUM(total_trx) |
+--------+--------------+------------+----------------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
| NULL | 2 | 2016-11-10 | 1003000 |
+--------+--------------+------------+----------------+
Ciri khas baris hasil WITH ROLLUP ini adalah adanya nilai
NULL pada kolom yang ada pada klausa GROUP BY (pada
contoh diatas kolom id_trx pada baris total), sedangkan nilai
pada kolom lain (yang tidak ada fungsi agregasinya) biasanya
sama dengan nilai pada baris sebelumnya
Hasilnya adalah:
+---------+-----------+------+---------+-----------+
| bln_trx | id | nama | jml_trx | nilai_trx |
+---------+-----------+------+---------+-----------+
| 11 | 2 | Beta | 1 | 256000 |
| 11 | SUB TOTAL | Beta | 1 | 256000 |
| 3 | 1 | Alfa | 2 | 378000 |
| 3 | SUB TOTAL | Alfa | 2 | 378000 |
| 4 | 0 | NULL | 1 | 259000 |
| 4 | 2 | Beta | 1 | 110000 |
| 4 | SUB TOTAL | Beta | 2 | 369000 |
| NULL | SUB TOTAL | Beta | 5 | 1003000 |
+---------+-----------+------+---------+-----------+
Pada contoh diatas, kita berhasil mengubah nilai NULL pada kolom
id menjadi SUB TOTAL, namun kenapa nilai pada bln_trx tetap NULL?
Hasil:
+-------+-------+------+---------+-----------+
| bulan | id | nama | jml_trx | nilai_trx |
+-------+-------+------+---------+-----------+
| 3 | 1 | Alfa | 2 | 378000 |
| 3 | TOTAL | Alfa | 2 | 378000 |
| 4 | 0 | NULL | 1 | 259000 |
| 4 | 2 | Beta | 1 | 110000 |
| 4 | TOTAL | Beta | 2 | 369000 |
| 11 | 2 | Beta | 1 | 256000 |
| 11 | TOTAL | Beta | 1 | 256000 |
| TOTAL | TOTAL | Beta | 5 | 1003000 |
+-------+-------+------+---------+-----------+
Bagaimana querynya?
Seperti yang telah kita bahas pada BAB I, ketika MySQL menjalankan
GROUP BY, maka otomatis MySQL akan mengurutkan data
berdasarkan data kolom yang ada pada klausa GROUP BY, hal ini
disebut implisit order.
Tetapi…
Tetapi…. sejak MySQL 5.7 cara ini sudah deprecated yang artinya
akan dihilangkan pada versi berikutnya (entah kapan), sehingga jika
kita menggunakan teknik ini, maka kode yang kita buat tidak “aman”
yang artinya tidak akan berjalan pada MySQL versi terbaru.
Sejak MySQL versi 5.7, fitur ini deprecated, yang artinya akan
dihilangkan pada MySQL versi berikutnya, sehingga
Sudah bisa?
Baiklah, mari kita cocokkan. Query versi saya adalah sebagai berikut:
1. SELECT *
2. FROM
3. (SELECT MONTH(tgl_trx) AS bln_trx
4. , id_pelanggan AS id, nama
5. , COUNT(id_trx) AS jml_trx
6. , SUM(total_trx) AS nilai_trx
7. FROM penjualan
8. LEFT JOIN pelanggan USING (id_pelanggan)
9. WHERE YEAR(tgl_trx) = 2017
10. GROUP BY bln_trx, id_pelanggan
11. WITH ROLLUP
12. ) AS penjualan
13. ORDER BY bln_trx DESC, id DESC
Penjelasan:
Kenapa kembali ke nilai NULL? bukan kata kata TOTAL atau SUB
TOTAL? kita menggunakan nilai NULL agar mudah mengatur
posisi baris null, karena jika kita urutkan secara ascending, nilai
NULL akan selalu diatas sedangkan untuk descending akan
selalu dibawah
Silakan dicoba?
Hasil:
+-------+-----------+------+---------+-----------+
| bulan | id | nama | jml_trx | nilai_trx |
+-------+-----------+------+---------+-----------+
| 4 | 2 | Beta | 1 | 110000 |
| 4 | 0 | - | 1 | 259000 |
| 4 | SUB TOTAL | Beta | 2 | 369000 |
| 3 | 1 | Alfa | 2 | 378000 |
| 3 | SUB TOTAL | Alfa | 2 | 378000 |
| TOTAL | SUB TOTAL | Beta | 4 | 747000 |
+-------+-----------+------+---------+-----------+
Penjelasan: kita akan mengolah lagi tabel hasil query, sehingga mau
tidak mau kita harus menggunakan subquery
Real World….
Dalam dunia nyata, pengurutan data bisa sangat kompleks, misal
pada tabel hasil query diatas, selain terdapat baris total dan subtotal,
diata diurutkan lagi berdasarkan nilai_trx tertinggi
Bagaimana querynya?
Silakan dicoba, cara yang digunakan sudah dibahas pada bab bab
sebelumnya….
Sudah? Baik, mari kita cocokkan. Query versi saya adalah sebagai
berikut:
1. SET @nomor := 1;
2. SET @total := (SELECT SUM(total_trx) FROM penjualan);
3. SELECT @nomor := 1;
4. SELECT @total := (SELECT SUM(total_trx) FROM penjualan);
Note: jika nilai variable berupa query, maka query tersebut harus
diletakkan di dalam tanda kurung (baris 2 dan 4)
Ketentuan:
Variable hanya dapat diisi satu nilai. Jika nilai tersebut berupa
hasil query, maka data hasil query tersebut harus terdiri dari
satu nilai (satu kolom dan satu baris)
1. SET @no := 0;
2. SELECT @no := @no + 1 AS no_urut
3. , nama
4. , tgl_trx
5. FROM penjualan
6. LEFT JOIN pelanggan USING (id_pelanggan)
7. WHERE YEAR(tgl_trx) = 2017
8. ORDER BY tgl_trx
Yup, seperti yang telah kita pelajari, bahwa pertama kali yang
dieksekusi adalah klausa FROM
1. <?php
2. $sql = 'SELECT @no := @no + 1 AS no_urut
3. , nama
4. , tgl_trx
5. FROM (SELECT @no := 0) AS nomor
6. , penjualan
7. LEFT JOIN pelanggan USING (id_pelanggan)
8. WHERE YEAR(tgl_trx) = 2017
9. ORDER BY tgl_trx';
10. $query = mysqli_query($sql);
Bagaimana querynya?
Bagaimana querynya?
Oiya tabel yang kita gunakan adalah tabel penjualan sebagai berikut:
+--------+--------------+------------+-----------+
| id_trx | id_pelanggan | tgl_trx | total_trx |
+--------+--------------+------------+-----------+
| 1 | 1 | 2017-03-02 | 192000 |
| 2 | 1 | 2017-03-10 | 186000 |
| 3 | 0 | 2017-04-10 | 259000 |
| 4 | 2 | 2017-04-05 | 110000 |
| 5 | 2 | 2016-11-10 | 256000 |
+--------+--------------+------------+-----------+
Sudah bisa?
1. SELECT bulan
2. , jml_trx
3. , total_trx
4. , @akm := @akm + total_trx AS akumulasi
5. FROM
6. ( SELECT @akm :=0) AS akumulasi,
7. ( SELECT MONTH(tgl_trx) AS bulan
8. , COUNT(id_trx) AS jml_trx
9. , SUM(total_trx) AS total_trx
10. FROM penjualan
11. GROUP BY MONTH(tgl_trx)
12. ) AS penjualan
Bagaimana prosesnya?
Pertama…
Seperti prinsip yang telah kita pahami, pertama tama kita definisikan
klausa FROM
Kedua…
Sesuai prinsip yang kita pahami, kita definisikan klausa SELECT.
Kolom bulan, jml_trx, dan total_trx sudah ada pada tabel rekap
perbulan (tabel diatas), selanjutnya kita tinggal tambahkan kolom
Hasilnya…
+-------+---------+-----------+-----------+
| bulan | jml_trx | total_trx | akumulasi |
+-------+---------+-----------+-----------+
| 3 | 2 | 378000 | 378000 |
| 4 | 2 | 369000 | 747000 |
| 11 | 1 | 256000 | 1003000 |
+-------+---------+-----------+-----------+
Misal kita memiliki tabel buku yang berisi daftar buku yang terdapat
di sebuah perpustakaan dan tabel buku_pinjam yang berisi data
buku yang dipinjam. Data pada tabel buku adalah sebagai berikut:
+---------+--------------------------+----------+
| id_buku | judul_buku | kategori |
+---------+--------------------------+----------+
| 1 | Belajar Database | 1 |
| 2 | Belajar PHP dan MySQL | 2 |
| 3 | Query MySQL untuk Pemula | 1 |
+---------+--------------------------+----------+
Bagaimana querynya?
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. DATEDIFF (tgl_kembali, tgl_pinjam) AS lama_pinjam
5. FROM buku_pinjam
6. WHERE tgl_kembali != "0000-00-00"
Pengayaan…
Selanjutnya mari kita tambahkan kolom status dan kolom jml_sanksi
dengan kriteria:
Bagaimana querynya?
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. DATEDIFF (tgl_kembali, tgl_pinjam) AS lama_pinjam,
5. IF (DATEDIFF (tgl_kembali, tgl_pinjam) > 2
6. , "Terlambat", "Tidak Terlambat"
Melanjutkan contoh diatas, kali ini kita gunakan kolom alias untuk
membuat kolom status dan jml_sanksi
Bagaimana querynya?
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. lama_pinjam,
5. IF (lama_pinjam > 2,"Terlambat","Tidak Terlambat") AS
status,
Bagaimana querynya?
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. lama_pinjam,
5. IF (lama_pinjam > 2,1500 * (lama_pinjam - 2),0) AS
jml_sanksi
6. FROM (
7. SELECT *,
8. DATEDIFF (NOW(), tgl_pinjam) AS lama_pinjam
9. FROM buku_pinjam
10. ) AS buku_pinjam
11. WHERE tgl_kembali = "0000-00-00"
Lebih lanjut…
Selanjutnya, kita persempit lagi kriteria yaitu untuk buku dengan
kategori 1, maka lama peminjaman hanya boleh 1 hari, jika lebih dari
itu, akan dikenakan sanksi.
1. SELECT id_buku,
2. tgl_pinjam,
3. tgl_kembali,
4. lama_pinjam,
5. id_kategori,
6. CASE WHEN (lama_pinjam > 1 AND id_kategori = 1)
7. OR
8. (lama_pinjam > 2 AND id_kategori != 1)
9. THEN "Terlambat"
10. ELSE "Tidak Terlambat"
11. END AS status,
12. CASE WHEN lama_pinjam > 1 AND id_kategori = 1
13. THEN 2000 * (lama_pinjam - 1)
14. WHEN lama_pinjam > 2 AND id_kategori != 1
15. THEN 1500 * (lama_pinjam - 2)
16. ELSE 0
17. END AS jml_sanksi
18. FROM (
19. SELECT *,
20. DATEDIFF (tgl_kembali, tgl_pinjam) AS lama_pinjam
21. FROM buku_pinjam
22. ) AS buku_pinjam
23. LEFT JOIN buku USING (id_buku)
24. WHERE tgl_kembali != "0000-00-00"
Bagaimana Querynya?
Pada query diatas, kita gunakan fungsi TIME untuk mengambil data
waktu saja tanpa tanggal (hh:mm:ss), fungsi MIN untuk mengambil
waktu terkecil dan fungsi MAX untuk waktu terbesar.
Untuk itu, kita perlu batasi jam absen masuk dan jam absen pulang,
misal kita batasi jam absen masuk maksimal sebelum jam 12:00 dan
jam absen pulang minimal diatas jam 12:00. Query yang kita
jalankan:
Lebih Lanjut…
Selanjutnya kita buat kriteria baru, dimana jika absen sebelum jam
7:31 berarti belum terlambat, 07:31 s.d 08:00 Terlambat kategori I
(TLI), 08:01 s.d 12:00 terlambat kategori II (TLII), selanjutnya jika
absen sebelum jam 17:00 termasuk kategori pulang sebelum
waktunya (PSW).
1. SELECT id_pegawai,
2. jam_masuk,
3. CASE WHEN jam_masuk != "-"
4. THEN
5. CASE WHEN jam_masuk > "07:30:00"
6. AND jam_masuk <= "08:00:00"
7. THEN "TLI"
8. WHEN jam_masuk > "08:00:00"
9. AND jam_masuk <= "12:00:00"
10. THEN "TLII"
11. ELSE "-"
12. END
13. ELSE "-"
14. END AS ket_masuk,
15. jam_pulang,
16. CASE WHEN jam_pulang != "-" AND jam_pulang <"17:00:00"
17. THEN "PSW"
18. ELSE "-"
19. END AS ket_pulang
20. FROM (
21. SELECT *,
22. IF (TIME( MIN(waktu_absen) ) <= "12:00:00"
23. , TIME( MIN(waktu_absen) )
24. , "-"
25. ) AS jam_masuk,
26. IF (TIME( MAX(waktu_absen) ) > "12:00:00"
27. , TIME( MAX(waktu_absen) )
28. , "-"
29. )AS jam_pulang
30. FROM absensi
31. GROUP BY id_pegawai
32. ) AS absensi
Pada pegawai jaga malam, absen masuk dimulai pada sore atau
malam hari, sedangkan untuk absen pulang pada hari berikutnya
Tabel yang akan kita gunakan adalah tabel absensi_malam. Isi dari
tabel tersebut adalah sebagai berikut:
+----------+------------+---------------------+
| id_absen | id_pegawai | waktu_absen |
+----------+------------+---------------------+
| 1 | 1 | 2017-05-14 16:50:59 |
| 2 | 1 | 2017-05-14 16:55:12 |
Bagaimana querynya?
1. SELECT id_pegawai,
2. DATE(waktu_absen) AS tanggal,
3. IF (TIME( MAX(waktu_absen) ) <= "21:00:00"
4. AND TIME( MAX(waktu_absen) ) >= "15:00:00"
5. , MAX(waktu_absen)
6. , "-"
7. ) AS waktu_masuk,
8. (SELECT
9. IF (TIME( MIN(waktu_absen) ) > "05:00:00"
10. AND TIME( MIN(waktu_absen) ) < "09:00:00"
11. , MIN(waktu_absen)
12. , "-"
13. ) AS waktu_pulang
14. FROM absensi_malam am
15. WHERE DATE(waktu_absen)
16. = DATE(am1.waktu_absen) + INTERVAL 1 DAY
17. AND am1.id_pegawai = am.id_pegawai
18. ) AS waktu_pulang
19. FROM absensi_malam am1
20. GROUP BY id_pegawai, DATE(waktu_absen)
Lebih Lanjut…
Selanjutnya, seperti pada studi kasus sebelumnya, kita buat
keterangan untuk keterlambatan absen, yaitu:
Bagaimana Querynya?
1. SELECT id_pegawai,
2. tanggal,
3. waktu_masuk,
4. CASE WHEN waktu_masuk != "-"
5. THEN
6. CASE WHEN TIME(waktu_masuk) > "17:00:00"
7. AND TIME(waktu_masuk) <= "17:31:00"
8. THEN "TL1"
9. WHEN TIME(waktu_masuk) > "17:31:00"
10. AND TIME(waktu_masuk) <= "21:00:00"
11. THEN "TL2"
12. ELSE "-"
13. END
14. ELSE "TIDAK ABSEN"
15. END AS ket_masuk,
16. waktu_pulang,
17. CASE WHEN waktu_pulang = "-"
18. THEN "TIDAK ABSEN"
19. ELSE
20. IF (TIME(waktu_pulang) < "07:00:00", "PSW", "-")
21. END AS ket_pulang
Pada query diatas, subquery yang ada pada klausa FROM sama
persis dengan query sebelumnya yang menghasilkan tabel:
+------------+------------+---------------------+---------------------+
| id_pegawai | tanggal | waktu_masuk | waktu_pulang |
+------------+------------+---------------------+---------------------+
| 1 | 2017-05-14 | 2017-05-14 16:55:12 | 2017-05-15 07:17:04 |
| 1 | 2017-05-15 | - | - |
| 2 | 2017-05-14 | 2017-05-14 16:59:25 | 2017-05-15 07:01:00 |
| 2 | 2017-05-15 | 2017-05-15 16:47:00 | - |
| 3 | 2017-05-14 | 2017-05-14 17:01:00 | 2017-05-15 07:05:00 |
| 3 | 2017-05-15 | 2017-05-15 16:30:04 | - |
| 4 | 2017-05-14 | 2017-05-14 17:31:00 | - |
| 5 | 2017-05-14 | - | 2017-05-15 07:26:27 |
| 5 | 2017-05-15 | - | - |
+------------+------------+---------------------+---------------------+
Pada ket_masuk kita tes apakah waktu masuk tidak bernilai strip ( - ):
Pada ket_pulang, kita tes apakah kolom waktu pulang bernilai strip (-
), jika ya maka beri keterangan TIDAK ABSEN, jika tidak maka dengan
fungsi IF, kita tes nilai waktu pulang, jika kurang dari pukul 07:00:00
maka beri keterangan PSW, jika tidak beri keterangan strip (-).
Sebagai contoh misal kita memiliki tabel pelari yang berisi catatan
waktu pencapaian berlari. Adapun isi dari tabel pelari tersebut
adalah sebagai berikut:
+------+---------+-----------+------------+
| id | nama | percobaan | waktu_lari |
+------+---------+-----------+------------+
| 1 | Alfa | 1 | 00:00:35 |
| 2 | Alfa | 2 | 00:00:30 |
| 3 | Alfa | 3 | 00:00:29 |
| 4 | Beta | 1 | 00:00:33 |
| 5 | Beta | 2 | 00:00:31 |
| 6 | Beta | 3 | 00:00:30 |
| 7 | Charlie | 1 | 00:00:29 |
| 8 | Charlie | 2 | 00:00:28 |
| 9 | Charlie | 3 | 00:00:31 |
+------+---------+-----------+------------+
Bagaimana querynya?
Pada query diatas kita sudah sangat familiar dengan fungsi MIN,
MAX, dan AVG, sehingga mudah dipahami bagai mana cara kerja dan
alur query diatas.
Lebih lanjut…
Lebih lanjut, kita cari waktu minimal dan maksimal tersebut
diperoleh dari percobaan ke berapa. Tabel output yang kita inginkan
adalah sebagai berikut:
+---------+-----------+---------+------------+---------+-----------------+
| nama | waktu_min | perc_ke | waktu_maks | perc_ke | waktu_rata_rata |
+---------+-----------+---------+------------+---------+-----------------+
| Alfa | 00:00:29 | 3 | 00:00:35 | 1 | 31.3333 |
| Beta | 00:00:30 | 3 | 00:00:33 | 1 | 31.3333 |
| Charlie | 00:00:28 | 2 | 00:00:31 | 3 | 29.3333 |
+---------+-----------+---------+------------+---------+-----------------+
Bagaimana querynya?
1. SELECT nama,
2. waktu_min,
3. ( SELECT percobaan
4. FROM pelari AS p2
5. WHERE p2.waktu_lari = p1.waktu_min
6. AND p2.nama = p1.nama
7. ) AS perc_ke,
8. waktu_maks,
9. (SELECT percobaan
10. FROM pelari AS p2
11. WHERE p2.waktu_lari = p1.waktu_maks
12. AND p2.nama = p1.nama
13. ) AS perc_ke,
14. waktu_rata_rata
Pada query diatas, pertama kita buat temporary tabel (pada klausa
from) yang kita beri nama p1 dengan bentuk sama seperti pada
contoh sebelumnya:
+---------+---------------+----------------+-----------------+
| nama | waktu_min | waktu_maks | waktu_rata_rata |
+---------+---------------+----------------+-----------------+
| Alfa | 00:00:29 | 00:00:35 | 31.3333 |
| Beta | 00:00:30 | 00:00:33 | 31.3333 |
| Charlie | 00:00:28 | 00:00:31 | 29.3333 |
+---------+---------------+----------------+-----------------+
Kali ini kita akan membahas beberapa contoh bentuk table reporting
dengan query SQL yang dapat Anda gunakan sebagai ide
pemecahan masalah yang Anda hadapi.
kop_simpanan
Keterangan:
Pertama…
Untuk membuat query SQL-nya, pertama kita perlu mendefinisikan
tabel hasil klausa FROM.
Karena kita perlu dua tabel dan tabel hasil klausa FROM harus
berupa satu tabel, maka kita harus menggabungkan keduanya.
Kenapa demikian?
1. SELECT *
2. FROM kop_anggota
3. LEFT JOIN kop_simpanan USING(id_anggota)
Hasil:
+------------+--------------+--------+------------+-------------+--------+----------+
| id_anggota | nama_anggota | pokok | tgl_daftar | id_simpanan | wajib | sukarela |
+------------+--------------+--------+------------+-------------+--------+----------+
| 1 | Alfa | 100000 | 2017-05-21 | 1 | 150000 | 250000 |
| 2 | Beta | 100000 | 2017-05-22 | 2 | 150000 | 350000 |
| 3 | Charlie | 100000 | 2017-05-23 | 3 | 150000 | 300000 |
| 4 | Delta | 100000 | 2017-05-24 | 4 | 150000 | 200000 |
| 2 | Beta | 100000 | 2017-05-22 | 5 | 150000 | 300000 |
| 1 | Alfa | 100000 | 2017-05-21 | 6 | 150000 | 300000 |
| 4 | Delta | 100000 | 2017-05-24 | 7 | 150000 | 400000 |
| 3 | Charlie | 100000 | 2017-05-23 | 8 | 150000 | 350000 |
+------------+--------------+--------+------------+-------------+--------+----------+
Kedua…
Selanjutnya kita definisikan kolom pada klausa SELECT. Dari tabel
hasil klausa FROM, maka kita perlu menjumlahkan data simpanan
wajib dan simpanan sukarela per anggota, sehingga kita gunakan
fungsi SUM, sedangkan untuk simpanan pokok, kita tidak perlu
menjumlahkannya karena simpanan pokok hanya dibayar sekali.
1. SELECT nama_anggota
2. , pokok
3. , SUM(wajib) AS wajib
4. , SUM(sukarela) AS sukarela
5. , pokok + SUM(wajib) + SUM(sukarela) AS total
6. FROM kop_anggota
7. LEFT JOIN kop_simpanan USING(id_anggota)
8. GROUP BY id_anggota
Hasil:
+---------+--------+---------+----------+---------+
| nama | pokok | wajib | sukarela | total |
+---------+--------+---------+----------+---------+
| Alfa | 100000 | 300000 | 550000 | 950000 |
| Beta | 100000 | 300000 | 650000 | 1050000 |
| Charlie | 100000 | 300000 | 650000 | 1050000 |
| Delta | 100000 | 300000 | 600000 | 1000000 |
+---------+--------+---------+----------+---------+
Pada bab terdahulu pernah kita bahas bahwa untuk kolom non
agregasi (pada contoh diatas adalah kolom pokok)) data yang
diambil adalah data pada baris pertama dan karena data kolom
Cara Lain…
Banyak jalan menuju Roma, demikian juga dengan permasalahan
diatas.
Karena kita akan menampilkan data per anggota, sehingga data yang
berkaitan juga harus dibentuk per anggota. Bentuk hubungan one-
to-one nya tampak seperti gambar berikut:
1. SELECT nama_anggota
2. , pokok, wajib, sukarela
3. , pokok + wajib + sukarela AS total
4. FROM kop_anggota
5. LEFT JOIN
6. (
7. SELECT id_anggota
8. , SUM(wajib) AS wajib
9. , SUM(sukarela) AS sukarela
10. FROM kop_simpanan
11. GROUP BY id_anggota
12. ) AS simpanan USING (id_anggota)
Hasil:
+---------+--------+--------+----------+---------+
| nama | pokok | wajib | sukarela | total |
+---------+--------+--------+----------+---------+
| Alfa | 100000 | 300000 | 550000 | 950000 |
| Beta | 100000 | 300000 | 650000 | 1050000 |
| Charlie | 100000 | 300000 | 650000 | 1050000 |
| Delta | 100000 | 300000 | 600000 | 1000000 |
+---------+--------+--------+----------+---------+
Hasil:
+--------------+--------+---------+----------+---------+
| nama_anggota | pokok | wajib | sukarela | total |
+--------------+--------+---------+----------+---------+
| Alfa | 100000 | 300000 | 550000 | 950000 |
| Beta | 100000 | 300000 | 650000 | 1050000 |
| Charlie | 100000 | 300000 | 650000 | 1050000 |
| Delta | 100000 | 300000 | 600000 | 1000000 |
| TOTAL | 400000 | 1200000 | 2450000 | 4050000 |
+--------------+--------+---------+----------+---------+
Pada query diatas, query pertama yang kita gunakan adalah cara
alternatif (one to one relationship), karena lebih aman, dimana
simpanan pokoknya hanya ditampilkan sekali.
pjk_target
+----+-------------+-------+----------+------------+
| id | id_rekening | tahun | triwulan | target |
+----+-------------+-------+----------+------------+
| 1 | 1 | 2017 | 1 | 3345000000 |
| 2 | 1 | 2017 | 2 | 3150000000 |
| 3 | 1 | 2017 | 3 | 2725000000 |
| 4 | 1 | 2017 | 4 | 4074000000 |
| 5 | 2 | 2017 | 1 | 4250000000 |
| 6 | 2 | 2017 | 2 | 4725000000 |
| 7 | 2 | 2017 | 3 | 5304000000 |
| 8 | 2 | 2017 | 4 | 6432000000 |
| 9 | 3 | 2017 | 1 | 1125000000 |
| 10 | 3 | 2017 | 2 | 921200000 |
| .. | ... | ... | ... | ... |
+----+-------------+-------+----------+------------+
pjk_realisasi
+----+-------------+------------+-----------+
| id | id_rekening | tanggal | pemasukan |
+----+-------------+------------+-----------+
| 1 | 1 | 2017-01-01 | 30858422 |
| 2 | 1 | 2017-01-02 | 22472129 |
| 3 | 1 | 2017-01-03 | 23665179 |
| 4 | 1 | 2017-01-04 | 31702866 |
| 5 | 1 | 2017-01-05 | 28370283 |
| .. | ... | ... | ... |
+----+-------------+------------+-----------+
Keterangan:
Tabel pjk_target terdiri target tahun 2017 dan tahun 2016 yang
dibagi per triwulan (1 s.d 4)
Selanjutnya kita buat laporan realisasi masing masing jenis pajak per
triwulan khusus untuk tahun 2017. Output yang akan kita buat
adalah sebagai berikut:
+-------------+----------------+-------------+-------------+-------------+----------+
| id_rekening | nama_rekening | target | realisasi | sisa_target | persen |
+-------------+----------------+-------------+-------------+-------------+----------+
| 1 | Pajak Hotel | 13294000000 | 13414756255 | 0 | 100.9084 |
| 2 | Pajak Restoran | 20711000000 | 20803995651 | 0 | 100.4490 |
| 3 | Pajak Hiburan | 4619200000 | 5218201170 | 0 | 112.9676 |
| 4 | Pajak Reklame | 12156000000 | 12512550544 | 0 | 102.9331 |
| 5 | Pajak Parkir | 3040900000 | 3068045855 | 0 | 100.8927 |
| | TOTAL | 53821100000 | 55017549475 | 0 | 102.2230 |
+-------------+----------------+-------------+-------------+-------------+----------+
Lanjutan...
+-------------+---------------+-----------------+------------+
| target_tw1 | realisasi_tw1 | sisa_target_tw1 | persen_tw1 |
+-------------+---------------+-----------------+------------+
| 3345000000 | 2486377516 | 858622484 | 74.33 |
| 4250000000 | 3371797490 | 878202510 | 79.34 |
| 1125000000 | 428999622 | 696000378 | 38.13 |
| 2535000000 | 1735409153 | 799590847 | 68.46 |
| 725900000 | 638265925 | 87634075 | 87.93 |
| 11980900000 | 8660849706 | 3320050294 | 72.29 |
+-------------+---------------+-----------------+------------+
dst… s.d triwulan 4
Bagaimana querynya?
Pertama…
Pertama kita identifikasi tabel output untuk membuat bentuk tabel
pada klausa FROM. Pada tabel tersebut terdapat kolom nama
rekening, target, dan realisasi, sehingga kita perlu menghubungkan
ketiga tabel, bagaimana model penggabungannya?
Kali ini, kita gunakan join dan kita tempatkan tabel pjk_rekening di
paling kiri (karena kita akan menampilkan semua nama rekening).
Tabel pjk_target:
+-------------+-------------+------------+------------+------------+------------+
| id_rekening | target | target_tw1 | target_tw2 | target_tw3 | target_tw4 |
+-------------+-------------+------------+------------+------------+------------+
| 1 | 13294000000 | 3345000000 | 3150000000 | 2725000000 | 4074000000 |
| 2 | 20711000000 | 4250000000 | 4725000000 | 5304000000 | 6432000000 |
| 3 | 4619200000 | 1125000000 | 921200000 | 1250000000 | 1323000000 |
| 4 | 12156000000 | 2535000000 | 2243000000 | 3653000000 | 3725000000 |
| 5 | 3040900000 | 725900000 | 696400000 | 753200000 | 865400000 |
+-------------+-------------+------------+------------+------------+------------+
1. SELECT id_rekening,
2. SUM( target ) AS target,
3. SUM(IF (triwulan = 1, target, 0)) AS target_tw1,
4. SUM(IF (triwulan = 2, target, 0)) AS target_tw2,
5. SUM(IF (triwulan = 3, target, 0)) AS target_tw3,
6. SUM(IF (triwulan = 4, target, 0)) AS target_tw4
7. FROM pjk_target
8. WHERE tahun = 2017
9. GROUP BY id_rekening
Tabel pjk_realisasi:
+-------------+-------------+---------------+---------------+---------------+---------------+
| id_rekening | realisasi | realisasi_tw1 | realisasi_tw2 | realisasi_tw3 | realisasi_tw4 |
+-------------+-------------+---------------+---------------+---------------+---------------+
| 1 | 13414756255 | 2486377516 | 2530160543 | 3256605372 | 5141612824 |
| 2 | 20803995651 | 3371797490 | 4138996875 | 5809459112 | 7483742174 |
| 3 | 5218201170 | 428999622 | 533177637 | 1790684580 | 2465339331 |
| 4 | 12512550544 | 1735409153 | 1669410671 | 4212431261 | 4895299459 |
| 5 | 3068045855 | 638265925 | 634578723 | 811158996 | 984042211 |
+-------------+-------------+---------------+---------------+---------------+---------------+
1. SELECT ...
2. FROM pjk_rekening
3. LEFT JOIN
4. (
5. SELECT id_rekening,
6. SUM( target ) AS target,
7. SUM(IF (triwulan = 1, target, 0)) AS target_tw1,
8. SUM(IF (triwulan = 2, target, 0)) AS target_tw2,
9. SUM(IF (triwulan = 3, target, 0)) AS target_tw3,
10. SUM(IF (triwulan = 4, target, 0)) AS target_tw4
11. FROM pjk_target
12. WHERE tahun = 2017
13. GROUP BY id_rekening
14. ) AS target USING(id_rekening)
15. LEFT JOIN
16. (
17. SELECT id_rekening,
18. SUM( IF (YEAR(tanggal) = 2017, pemasukan, 0)
19. ) AS realisasi,
20. SUM(IF(tanggal >= '2017-01-01'
Kedua…
Selanjutnya setelah kita selesai menyusun bentuk tabel pada klausa
FROM, maka kita perlu menyusun klausa SELECT
Nah, agar lebih mudah mengaturnya, kita buat tabel total tersendiri,
kemudian kita gabungkan dengan tabel utama. Query untuk
membuat tabel total adalah sebagai berikut:
Latihan:
Sebagai latihan silakan coba untuk membanding pencapaian tahun
2017 dengan 2016 kemudian tampilkan persentase pertumbuhan
penerimaannya.
Pada tabel diatas, terdapat data total untuk tiap-tiap jenis pajak
disertai dengan rincian pendapatan per triwulannya, untuk itu perlu
Query diatas mirip dengan query pada table report II. Sedangkan
query untuk tabel ke 2 adalah sebagai berikut:
1. SELECT id_rekening
2. , CONCAT('Triwulan ', triwulan) AS triwulan
3. , target
4. , realisasi, ROUND(realisasi/target*100, 2) AS persen
5. FROM pjk_rekening
6. LEFT JOIN (
7. SELECT *
8. FROM pjk_target
9. WHERE tahun = 2017
10. ) AS target USING(id_rekening)
11. LEFT JOIN
12. (
13. SELECT id_rekening,
14. CASE WHEN tanggal >= '2017-01-01'
15. AND tanggal <= '2017-03-31'
16. THEN 1
17. WHEN tanggal >= '2017-04-01'
18. AND tanggal <= '2017-06-31'
19. THEN 2
20. WHEN tanggal >= '2017-07-01'
21. AND tanggal <= '2017-09-31'
22. THEN 3
23. WHEN tanggal >= '2017-10-01'
24. AND tanggal <= '2017-12-31'
25. THEN 4
26. END AS triwulan
27. ,SUM(pemasukan) AS realisasi
1. QUERY 1
2. UNION ALL
3. QUERY 2
4. ORDER BY id_rekening, nama_rekening
Namun demikian, cara berfikir kita tetap sama yaitu kita buat dua
buah tabel: tabel total dan tabel total per triwulan, kemudian kita
gunakan UNION ALL untuk menggabungkan kedua tabel tersebut.
Tabel pertama…
Tabel pertama kita dapatkan dengan query berikut:
1. SELECT *
2. FROM
3. (
4. SELECT id_rekening, target AS target_2017
5. FROM pjk_target
6. WHERE tahun = 2017
7. GROUP BY id_rekening
) AS target_2017
8.
LEFT JOIN
9.
( SELECT id_rekening, target AS target_2016
10. FROM pjk_target
11. WHERE tahun = 2016
12. GROUP BY id_rekening
13. ) AS target_2016 USING (id_rekening)
14.
Ket: Istilah Self Join mengacu pada bentuk join dimana tabel yang
digabungkan adalah tabel yang sama.
Tabel kedua…
Tabel kedua, yaitu rekap pemasukan per triwulan, kita dapatkan
dengan menjalankan query berikut:
1. SELECT id_rekening
2. , CONCAT('Triwulan ', triwulan) AS triwulan
3. , target_2017, realisasi_2017
14.4. Keterbatasan
Sejauh ini kita telah membahas berbagai model penyajian data
dengan query SQL.
Kenapa?
Jika Anda tidak familiar dengan PHP, Anda dapat mengambil konsep
atau alur logika yang ada pada setiap kasus yang dibahas, sehingga
dapat diterapkan pada aplikasi Anda.
Misal kita ingin menampilkan data nama barang dan stok barang
yang ada pada tabel barang. SQL yang kita gunakan adalah:
Jika kita jalankan pada software database manager, hasil yang kita
peroleh adalah sebagai berikut:
+-----------+-------------+------+-------+
| kd_barang | nama_barang | stok | harga |
+-----------+-------------+------+-------+
| 1 | Mouse | 14 | 76000 |
| 2 | Flashdisk | 15 | 55000 |
| 3 | Mousepad | 17 | 35000 |
| 4 | Keyboard | 12 | 80000 |
| 5 | Kabel VGA | 7 | 45000 |
+-----------+-------------+------+-------+
1. <?php
2. // Koneksi
3. $conn = mysqli_connect('localhost', 'root', '',
4. 'tutorial_trik');
5.
6. // Menjalankan query
7. $query = mysqli_query($conn, 'SELECT * FROM barang');
8.
9. // Menampilkan data
10. while($row = mysqli_fetch_assoc($query)) {
11. echo $row['nama_barang'] . ' ' . $row['harga'] .
12. '<br/>';
13. }
Selanjutnya, dengan loop while kita ambil data tersebut satu persatu
urut mulai dari atas, hingga terakhir.
Pada aplikasi, terdapat opsi untuk memilih wilayah, bulan, dan tahun
penjualan. Opsi ini digunakan untuk memfilter data yang akan
ditampilkan.
Tabel Database…
Tabel database yang kita gunakan hanya satu, yaitu tabel sales
dengan data sebagai berikut:
+--------+---------+------------+----------+-----------+
| id_trx | nama | tgl_trx | area | nilai_trx |
+--------+---------+------------+----------+-----------+
| 1 | Alfa | 2017-01-10 | Jakarta | 250000 |
| 2 | Charlie | 2017-01-02 | Medan | 175000 |
| 3 | Bravo | 2017-01-01 | Jakarta | 310000 |
| 4 | Bravo | 2017-02-04 | Jakarta | 250000 |
| 5 | Alfa | 2017-01-15 | Jakarta | 125000 |
| ... | ... | ... | ... | ... |
+--------+---------+------------+----------+-----------+
Model tabel diatas tentu tidak ideal dimana untuk nama dan area
seharusnya dibuat tabel tersendiri kemudian berelasi dengan tabel
Pada script diatas, kita membuat opsi bulan dan tahun dari array.
Hal ini akan memudahkan kita untuk membuat dan memperbaiki
kode, salah satunya memberi atribut selected="selected" pada opsi
yang dipilih ketika form disubmit
SQL Query …
Selanjutnya ketika form disubmit (tombol submit di klik), kita jalan
query MySQL untuk mengambil data dari database sesuai dengan
opsi yang dipilih.
1. SELECT nama,
2. area,
3. COUNT(nilai_trx) AS jml_trx,
4. SUM(nilai_trx) AS total_trx
1. if (isset($_GET['submit']))
2. {
3. // WHERE
4. $where_area = $_GET['area'] != 'Semua' ? ' AND area =
5. "' . $_GET['area'] . '"' : '';
6. $where_bulan = $_GET['bulan'] != 'semua' ? ' AND
7. MONTH(tgl_trx) = ' . $_GET['bulan'] : '';
8.
9. // QUERY
10. $sql = '
11. SELECT
12. nama,
13. area,
14. COUNT(nilai_trx) AS jml_trx,
15. SUM(nilai_trx) AS total_trx
16. FROM sales
17. WHERE YEAR(tgl_trx) = ' . $_GET['tahun'] . $where_bulan .
18. $where_area
19. . ' GROUP BY sales.area, nama';
20.
21. $query = mysqli_query($conn, $sql);
22.
23. // RESULT
24. if (!$query) {
25. $error[] = mysqli_error($conn) . '<br/><strong>SQL
26. Query</strong>: ' . $sql;
27. } else {
28. $num_rows = mysqli_num_rows($query);
29. if (!$num_rows) {
30. $warning[] = 'Data tidak ditemukan';
31. } else {
32. $hasil_query = true;
33. while($row = mysqli_fetch_array($query)) {
34. $result[$row['area']][] = $row;
35. }
36. }
37. }
Baris subtotalnya akan kita buat dengan script PHP. Tapi, bukankah
bisa menggunakan query sql?
1. SELECT nama,
2. area,
3. COUNT(nilai_trx) AS jml_trx,
4. SUM(nilai_trx) AS total_trx
Menampilkan Data
Bentuk tampilan data yang akan kita buat sedikit berbeda dengan
tabel output hasil query, dimana baris area ditampilkan tersendiri.
1. if (isset($_GET['submit'])) {
2. if ($hasil_query)
3. {
4. $thead = '<th>No</th>
5. <th>Nama</th>
6. <th>Jml Unit</th>
7. <th>Total Nilai</th>';
8.
9. echo '
10. <div class="table-responsive">
11. <table>
12. <thead>' . $thead . '</thead>
13. <tbody>';
14.
15. while($row = mysqli_fetch_array($query)) {
16. $result[$row['area']][] = $row;
17. }
18.
19. $no = 1;
20. foreach($result as $area => $arr)
21. {
)
[Medan] => Array
(
[0] => Array
(
[0] => Charlie
[nama] => Charlie
[1] => Medan
[area] => Medan
[2] => 6
[jml_trx] => 6
[3] => 1875000
[total_trx] => 1875000
)
Pada array diatas, terlihat bahwa data array dikelompokkan per area
(index berupa nama area) sehingga akan memudahkan ketika
menampilkan data per area.
Lanjutan…
Selanjutnya, coba Anda tambahkan opsi untuk mengubah urutan
data, dimana user dapat memilih data diurutkan berdasarkan total
transaksi, per area, dan nama area, baik secara descending maupun
ascending.
Sudah?
Pada bentuk ini, kita akan mengurutkan data dalam satu kolom lebih
dari satu arah, perhatikan ilustrasi berikut:
Model seperti ini tidak dapat dilakukan dengan SQL, karena SQL
hanya dapat mengurutkan satu arah, ascending semua atau
descending semua.
1. SELECT
2. area,
3. COUNT(nilai_trx) AS jml_trx,
4. SUM(nilai_trx) AS total_trx
5. FROM sales
6. WHERE YEAR(tgl_trx) = 2017
7. GROUP BY area
1. SELECT nama,
2. area,
3. COUNT(nilai_trx) AS jml_trx,
4. SUM(nilai_trx) AS total_trx
5. FROM sales
6. WHERE YEAR(tgl_trx) = 2017
7. GROUP BY sales.area, nama
1. $sql_nama = '
2. SELECT
3. nama,
4. area,
5. COUNT(nilai_trx) AS jml_trx,
6. SUM(nilai_trx) AS total_trx
7. FROM sales
8. WHERE YEAR(tgl_trx) = ' . $_GET['tahun'] . $where_bulan .
9. $where_area. '
10. GROUP BY sales.area, nama';
1. while($row = mysqli_fetch_array($query_nama)) {
2. $result_nama[$row['area']][] = $row;
3. }
Pada sisi aplikasi, terdapat opsi untuk memilih bulan dan tahun. Opsi
ini nantinya digunakan untuk mengambil data pada bulan dan tahun
tertentu.
Data dan query yang kita gunakan sama dengan yang digunakan
pada BAB 13 Menguasai DATE TIME sub-bab 13.3 Studi Kasus #3.
TM, jika pegawai tidak masuk (tidak ada absen masuk maupun
pulang
Tabel Database…
Tabel yang kita gunakan adalah tabel absensi_pegawai dan
absensi_data dengan data sebagai berikut:
absensi_data
+----+------------+---------------------+
| id | id_pegawai | waktu_absen |
absensi_pegawai
+------------+---------+-------------+
| id_pegawai | nama | alamat |
+------------+---------+-------------+
| 1 | Alfa | Jakarta |
| 2 | Beta | Semarang |
| 3 | Charlie | Surabaya |
| 4 | Delta | Yogayakarta |
| 5 | Erdhi | Surakarta |
| ... | ... | ... |
+------------+---------+-------------+
Kode HTML dan PHP diatas jika dijalankan akan menghasilkan kode
HTML sebagai berikut:
SQL Query …
Selanjutnya ketika form disubmit (tombol submit di klik), kita jalankan
query MySQL untuk mengambil data dari database sesuai dengan
opsi yang dipilih oleh user.
SQL query yang kita gunakan mirip dengan yang kita gunakan pada
BAB 13 subbab 13.2
1. if (isset($_GET['submit']))
2. {
3. require_once('config.php');
4. // KONEKSI
5. $conn = @mysqli_connect(DB_HOST, DB_USER, DB_PASS,
6. DB_NAME);
7. if (!$conn) {
Pada script diatas, pada klausa WHERE kita tambahkan scrit WHERE
MONTH(tanggal) = '.$_GET['bulan'].' AND YEAR(tanggal) = '
. $_GET['tahun'];, script tersebut akan memfilter data sesuai
dengan bulan dan tahun yang dipilih. Misal jika data yang dipilih
bulan maret 2017, maka script berubah menjadi WHERE
MONTH(tanggal) = 3 AND YEAR(tanggal) = 2017';
Menampilkan data
Bagian terpenting adalah bagian menampilkan data, karena bagian
ini akan mengkonversi tabel hasil query menjadi tabel output sesuai
dengan yang telah kita tentukan diawal.
1. if (isset($_POST['submit'])) {
2. if ($hasil_query)
3. {
4. while($row = mysqli_fetch_assoc($query)) {
5. $tgl = (int) substr($row['tanggal'],-2);
6. $result[$row['id_pegawai']]['nama'] = $row['nama'];
7. $result[$row['id_pegawai']][$tgl] = $row;
8. }
9.
10. $jml_hari = date('t');
11. $thead = '<th>No</th>
12. <th>Nama</th>';
13.
14. for($i=1; $i<=$jml_hari;$i++) {
15. $thead .= '<th>'. $i .'</th>';
16. }
17.
18. echo '
19. <div class="table-responsive">
20. <table>
21. <thead>' . $thead . '</thead>
22. <tbody>';
23.
24. $no = 1;
25. foreach($result as $id_pegawai => $hari_absen) {
26. echo '<tr>
27. <td>' . $no . '</td>
28. <td>' . $hari_absen['nama'] . '</td>';
29.
Pada query diatas, pertama tama hasil query kita simpan dalam
variabel $result. Variabel ini berisi data array dengan bentuk
sedemikian rupa sehingga memudahkan kita untuk menampilkan
data per tanggal.
1. while($row = mysqli_fetch_assoc($query)) {
2. $tgl = (int) substr($row['tanggal'],-2);
3. $result[$row['id_pegawai']]['nama'] = $row['nama'];
Bentuk array yang ada pada variabel result adalah sebagai berikut:
Array
(
[1] => Array
(
[nama] => Alfa
[1] => Array
(
[id_pegawai] => 1
[nama] => Alfa
[tanggal] => 2017-02-01
[jam_masuk] => 07:16:32
[ket_masuk] => -
[jam_pulang] => 17:14:04
[ket_pulang] => -
)
Selanjunya kita loop hari mulai dari tanggal 1 dengan tanggal terakhir
dari bulan yang dipilih. Tanggal terakhir pada bulan yang dipilih
diperoleh dari fungsi date('t', strtotime($_GET['tahun'].'-
'.$_GET['bulan'].'-01')), misal: date('t', strtotime('2017-
03-01')), hasilnya kita simpan pada variabel $jml_hari
Selanjutnya didalam loop tersebut kita cek tanggal pada tiap tiap
pegawai, jika tanggalnya ada, berarti pegawai tersebut absen dan
kita cek ket_masuk dan ket_pulangnya, jika tidak ada, kita beri
keterangan TM, bentuk script PHPnya adalah sebagai berikut:
1. for($i=1; $i<=$jml_hari;$i++) {
2. if(key_exists($i, $hari_absen)) {
3.
4. $ket = array();
5. if ($hari_absen[$i]['ket_masuk'] != '-') {
6. $ket[] =$hari_absen[$i]['ket_masuk'];
7. }
8.
9. if ($hari_absen[$i]['ket_pulang'] != '-') {
10. $ket[] =$hari_absen[$i]['ket_masuk'];
11. }
12.
13. if ($ket) {
14. $text = join($ket, ', ');
15. } else {
16. $text = '-';
17. }
18. } else {
19. $text = 'TM';
Tabel Database…
Tabel database yang akan kita gunakan adalah tabel pjk_rekening
dan pjk_realisasi dengan contoh data sebagai berikut:
pjk_rekening
+-------------+----------------+
| id_rekening | nama_rekening |
+-------------+----------------+
| 1 | Pajak Hotel |
| 2 | Pajak Restoran |
| 3 | Pajak Hiburan |
| 4 | Pajak Reklame |
| 5 | Pajak Parkir |
+-------------+----------------+
pjk_realisasi
+----+-------------+------------+-----------+
| id | id_rekening | tanggal | pemasukan |
+----+-------------+------------+-----------+
| 1 | 1 | 2016-01-01 | 13982658 |
| 2 | 1 | 2016-01-02 | 14873263 |
| 3 | 1 | 2016-01-03 | 20594174 |
| 4 | 1 | 2016-01-04 | 22998050 |
| 5 | 1 | 2016-01-05 | 14376610 |
|... | ... | ... | ... |
+----+-------------+------------+-----------+
Pada kode diatas, kita membuat opsi jenis rekening dari hasil query
database kemudian dengan loop while kita susun HTML option nya,
SQL Query …
Selanjutnya ketika form disubmit (tombol submit di klik), kita ambil
data dari database sesuai dengan parameter yang dipilih.
1. SELECT nama_rekening
2. , SUM(IF(MONTH(tanggal)=1,pemasukan, NULL)) AS bulan_1
3. , SUM(IF(MONTH(tanggal)=2,pemasukan, NULL)) AS bulan_2
4. , SUM(IF(MONTH(tanggal)=3,pemasukan, NULL)) AS bulan_3
5. , SUM(IF(MONTH(tanggal)=4,pemasukan, NULL)) AS bulan_4
1. if (isset($_GET['submit']))
2. {
3. $sql = 'SELECT nama_rekening';
4.
5. $total = $kolom_total = '';
6. for($i=1; $i<=12; $i++) {
7. $sql .= ', SUM(IF(MONTH(tanggal)='.$i.',pemasukan,
8. NULL)) AS bulan_' . $i;
9. $kolom_total .=
10. 'SUM(IF(MONTH(tanggal)='.$i.',pemasukan, NULL)) + ';
11. }
12. $sql .= ', ' . rtrim($kolom_total, '+ ') . ' AS total';
13.
14. $sql .= ' FROM pjk_rekening
15. LEFT JOIN pjk_realisasi USING(id_rekening)
16. WHERE YEAR(tanggal) = ' . $_GET['tahun'];
17.
Pada form terdapat opsi pilihan kode rekening dan tahun, pada
script diatas, kita akomodir opsi tersebut dengan menambahkan
WHERE YEAR(tanggal) = ' . $_GET['tahun'] baris 16 untuk
menangkap parameter tahun dan if ($_GET['jns_rekening'] !=
'semua') baris 18 untuk menangkap opsi jenis rekening
Menampilkan data
Bentuk tampilan data yang akan kita buat sudah sama dengan tabel
output hasil query, sehingga untuk menampilkannya ke dalam
bentuk tabel html, tidak memerlukan pengolahan lebih lanjut.
1. if ($hasil_query)
2. {
3. $thead = '<th>No</th>
4. <th>Rekening</th>';
5.
6. for($i=1; $i<=12;$i++) {
7. $thead .= '<th>'. $bulan[$i] .'</th>';
8. $total_bulan[$i] = 0; // identifikasi awal agar tidak
muncul pesan warning
9. }
10. $thead .= '<th>TOTAL</th>';
11.
12. echo '
13. <div class="table-responsive">
14. <table>
15. <thead>' . $thead . '</thead>
16. <tbody>';
17.
18. $no = 1;
19. $total_all = 0;
20. while($row = mysqli_fetch_assoc($query)) {
21. echo '<tr>
22. <td>' . $no . '</td>
23. <td>' . $row['nama_rekening'] . '</td>';
24. for($i=1; $i<=12;$i++) {
25.
Namun jika tahun yang dipilih hanya satu, maka tampilannya sama
seperti pada contoh sebelumnya
Ketika disubmit dan yang dientang tahun 2017 dan 2016 maka akan
terbentuk query seperti berikut ini:
1. SELECT nama_rekening
2. , bulan_1_2017
3. , ROUND( (bulan_1_2017 - bulan_1_2016)
4. / bulan_1_2016 * 100, 2) AS persen_1_2017
5. , bulan_2_2017
6. , ROUND( (bulan_2_2017 - bulan_2_2016)
1. if (isset($_GET['submit']))
2. {
3. // CEK APAKAH ADA TAHUN YANG DICETANG
4. $form_error = '';
5. $year_checked = false;
6. foreach ($year_options as $year) {
7. if (key_exists($year, $_GET)) {
8. $year_checked = true;
9. $used_year[] = $year;
10. }
11. }
12. if (!$year_checked) {
13. $error[] = 'Tahun harus dipilih';
14. }
15.
16. // Query
17. $select = '';
18. $subquery = 'SELECT id_rekening';
19.
20. $total = '';
Pada script diatas, tahun yang dicentang kita simpan pada variabel
$used_year dengan bentuk array.
Selain itu, kita tambahkan fitur pada form yang memungkin user
untuk memilih model pengurutan data, apakah data diurutkan
berdasarkan realisasi dalam rupiah, persentase pencapaian, atau
nama rekening (jenis pajak) baik secara ascending maupun
descending.
Tabel Database
Tabel database yang digunakan adalah tabel pjk_rekening, pjk_target
dan pjk_realisasi dengan data sebagai berikut:
pjk_rekening
+-------------+----------------+
| id_rekening | nama_rekening |
+-------------+----------------+
| 1 | Pajak Hotel |
| 2 | Pajak Restoran |
| 3 | Pajak Hiburan |
| 4 | Pajak Reklame |
| 5 | Pajak Parkir |
+-------------+----------------+
Pjk_target
+----+-------------+-------+----------+------------+
| id | id_rekening | tahun | triwulan | target |
+----+-------------+-------+----------+------------+
| 1 | 1 | 2017 | 1 | 3345000000 |
| 2 | 1 | 2017 | 2 | 3150000000 |
| 3 | 1 | 2017 | 3 | 2725000000 |
| 4 | 1 | 2017 | 4 | 4074000000 |
|... | ... | ... | ... | ... |
Script diatas, untuk membuat opsi jenis rekening, kita ambil data
tabel pjk_rekening kemudian dengan loop while kita susun HTML
option nya, sedangkan opsi yang lain, seperti tahun dan urutkan, kita
gunakan array.
SQL Query
Selanjutnya ketika form disubmit (tombol submit di klik), aplikasi
akan mengambil data dari database sesuai dengan parameter yang
dipilih oleh user
Pada table reporting ini, kita menggunakan dua query, yaitu query
untuk total per rekening dan query untuk rekap per triwulan, kenapa
perlu dua query?
Seperti yang telah kita bahas pada bab 14.4 bahwa query memiliki
keterbatasan, tidak semua permasalahan dapat diselesaikan hanya
menggunakan query.
Pada kasus ini, kita akan mengurutkan data hanya pada total masing
masing jenis pajak berdasarkan jumlah penerimaan, persen
pencapaian, atau nama jenis pajak, sedangkan untuk triwulannya
kita urutkan tersendiri.
Kasus diatas sama seperti kasus pada BAB 15.2 Table Reporting I
dimana kita mengurutkan data sekaligus berdasarkan sub total dan
nama sales
Query pertama
Query pertama adalah query untuk menghitung total masing masing
jenis pajak. Querynya adalah sebagai berikut:
Pada script diatas, kita simpan opsi pilihan jenis rekening pada
variabel $where_rekening karena opsi tersebut mengandung kondisi
dimana jika jenis rekening tidak bernilai semua, maka kita isi variabel
tersebut dengan kondisi AND id_rekening = "' .
$_GET['jns_rekening'] . '" '
Pada baris 22, kita gunakan WHERE 1=1. Hal ini merupakan trik yang
umum digunakan untuk memudahkan mendefinisikan klausa where
yang berubah ubah. Pada contoh diatas, kita variabel
$where_rekening bernilai kosong, maka klausa WHERE berbentuk
WHERE 1=1, jika tidak maka isinya WHERE 1=1 AND id_rekening = 1.
Jika tanpa 1=1, maka klausa WHERE menjadi WHERE AND
id_rekening = 1, hal ini akan mengakibatkan query error.
Jika query diatas dijalankan, maka tabel output yang kita peroleh
adalah:
+-------------+----------------+-------------+-------------+--------+
| id_rekening | nama_rekening | target | realisasi | persen |
+-------------+----------------+-------------+-------------+--------+
| 2 | Pajak Restoran | 20711000000 | 20803995651 | 100.45 |
| 1 | Pajak Hotel | 13294000000 | 13414756255 | 100.91 |
| 4 | Pajak Reklame | 12156000000 | 12512550544 | 102.93 |
| 3 | Pajak Hiburan | 4619200000 | 5218201170 | 112.97 |
| 5 | Pajak Parkir | 3040900000 | 3068045855 | 100.89 |
+-------------+----------------+-------------+-------------+--------+
1. SELECT id_rekening
2. , CONCAT("Triwulan ", triwulan) AS triwulan
3. , target
4. , realisasi, ROUND(realisasi/target*100, 2) AS persen
5. FROM pjk_rekening
6. LEFT JOIN (
7. SELECT *
8. FROM pjk_target
9. WHERE tahun = 2017
10. ) AS target USING(id_rekening)
11. LEFT JOIN
12. (
13. SELECT id_rekening,
14. CASE WHEN tanggal >= "2017-01-01"
15. AND tanggal <= "2017-03-31"
16. THEN 1
17. WHEN tanggal >= "2017-04-01"
18. AND tanggal <= "2017-06-31"
19. THEN 2
20. WHEN tanggal >= "2017-07-01"
21. AND tanggal <= "2017-09-31"
22. THEN 3
23. WHEN tanggal >= "2017-10-01"
24. AND tanggal <= "2017-12-31"
25. THEN 4
26. END AS triwulan
27. ,SUM(pemasukan) AS realisasi
28. FROM pjk_realisasi
29. WHERE YEAR(tanggal) = 2017
30. GROUP BY id_rekening,
31. CASE WHEN tanggal >= "2017-01-01"
32. AND tanggal <= "2017-03-31"
33. THEN 1
34. WHEN tanggal >= "2017-04-01"
35. AND tanggal <= "2017-06-31"
36. THEN 2
37. WHEN tanggal >= "2017-07-01"
38. AND tanggal <= "2017-09-31"
39. THEN 3
40. WHEN tanggal >= "2017-10-01"
Bentuk query diatas sudah kita bahas pada bab 14.3. Jika dikonversi
ke script PHP, bentuknya menjadi:
1. $sql_triwulan =
2. 'SELECT id_rekening
3. , CONCAT("Triwulan ", triwulan) AS triwulan
4. , target
5. , realisasi, ROUND(realisasi/target*100, 2) AS persen
6. FROM pjk_rekening
7. LEFT JOIN (
8. SELECT *
9. FROM pjk_target
10. WHERE tahun = '.$_GET['tahun'] . $where_rekening . '
11. ) AS target USING(id_rekening)
12. LEFT JOIN
13. (
14. SELECT id_rekening,
15. CASE WHEN tanggal >= "'. $_GET['tahun'] .'-01-01"
16. AND tanggal <= "'. $_GET['tahun'] .'-03-31"
17. THEN 1
18. WHEN tanggal >= "'. $_GET['tahun'] .'-04-01"
19. AND tanggal <= "'. $_GET['tahun'] .'-06-31"
20. THEN 2
21. WHEN tanggal >= "'. $_GET['tahun'] .'-07-01"
22. AND tanggal <= "'. $_GET['tahun'] .'-09-31"
23. THEN 3
24. WHEN tanggal >= "'. $_GET['tahun'] .'-10-01"
25. AND tanggal <= "'. $_GET['tahun'] .'-12-31"
26. THEN 4
27. END AS triwulan
28. ,SUM(pemasukan) AS realisasi
29. FROM pjk_realisasi
30. WHERE YEAR(tanggal)='.$_GET['tahun']. $where_rekening . '
31. GROUP BY id_rekening,
32. CASE WHEN tanggal >= "'. $_GET['tahun'] .'-01-01"
33. AND tanggal <= "'. $_GET['tahun'] .'-03-31"
34. THEN 1
35. WHEN tanggal >= "'. $_GET['tahun'] .'-04-01"
36. AND tanggal <= "'. $_GET['tahun'] .'-06-31"
Menampilkan data
Selanjutnya kita buat script untuk menampilkan data. Untuk
menggabungkan hasil dari kedua query, maka kita perlu
menghubungkan keduanya menggunakan index id_rekening. Pada
query pertama (total per rekening), hasil query dari script PHP
berbentuk sebagai berikut:
Array
(
[0] => Array
(
[id_rekening] => 3
[nama_rekening] => Pajak Hiburan
[target] => 4619200000
[realisasi] => 5218201170
[persen] => 112.97
)
1. while($row = mysqli_fetch_assoc($query_triwulan)) {
2. $result_triwulan[$row['id_rekening']][]= $row;
Pada script diatas, data array per id rekening kita simpan pada
variabel $result_triwulan.
1. if (isset($_GET['submit'])) {
2. if ($hasil_query)
3. {
4. $thead = '<tr>
5. <th>No</th>
6. <th>Nama Rekening</th>
7. <th>Target</th>
8. <th>Realisasi</th>
9. <th>Pencpaian(%)</th>
10. </tr>';
11.
12. echo '
13. <div class="table-responsive">
14. <table>
15. <thead>' . $thead . ' </thead>
16. <tbody>';
17.
18. while($row = mysqli_fetch_assoc($query_triwulan)) {
19. $result_triwulan[$row['id_rekening']][]= $row;
20. }
21.
22. $no = 1;
23. while($row = mysqli_fetch_assoc($query_total)) {
24. echo '<tr class="subtotal">
25. <td>' . $no . '</td>
26. <td>' . $row['nama_rekening'] . '</td>
27. <td class="right">' .
28. number_format($row['target'], 0, ',', '.') . '</td>
29. <td class="right">' .
30. number_format($row['realisasi'], 0, ',', '.') . '</td>
31. <td class="right">'.$row['persen'].'</td>
32. </tr>';
33. foreach ($result_triwulan[$row['id_rekening']] as $val) {
34. echo '<tr>
35. <td></td>
36. <td>' . $val['triwulan'] . '</td>
37.
Pada query diatas, pertama kita loop hasil query pada $query total
untuk menampilkan data total per rekening, disaat yang sama kita
ambil data per triwulannya berdasarkan index id_rekening
$result_triwulan[$row['id_rekening']], jika id_rekening 1, maka
data yang diambil adalah $result_triwulan[1]
Lebih Lanjut…
Sama seperti Table Reporting III, terkadang kita perlu
menyandingkan data beberapa tahun sekaligus. Mari kita ubah form
yang telah kita buat menjadi seperti berikut
Ketika disubmit dan yang dicentang tahun 2017 dan 2016 maka
bentuk data yang ditampilkan adalah sebagai berikut:
Gambar 15.17 Tampilan Tabel Hasil Form Submit Jika Tahun Yang dipilih
Lebih Dari Satu
Pada gambar diatas terlihat bahwa pada tahun 2017 terdapat kolom
growth yang merupakan pertumbuhan realisasi dari tahun
sebelumnya
Gambar 15.18 Tampilan Tabel Hasil Form Submit Jika Tahun Yang dipilih
Hanya Satu
SQL Query…
Sama seperti sebelumnya, untuk query SQL nya kita pisah antara
query untuk total per rekening dan query untuk rekap per
triwulannya
Jika dicentang beberapa tahun, maka query total per rekening nya
adalah sebagai berikut:
Kita perlu membuat dua query karena jika yang dicentang lebih dari
satu tahun kita perlu membuat query untuk growth.
Meskipun pada contoh kali ini tidak ada opsi untuk mengurutkan
data berdasarkan growth, kita tetap menggunakan dua query untuk
memberi gambaran kepada Anda bagaimana penerapan dua query
dalam aplikasi.
Script pertama kita buat query total per rekening. Ccript PHP nya
adalah sebagai berikut:
1. $sql_total = '
2. SELECT id_rekening, nama_rekening';
3. arsort($used_year);
4. $keys = array_keys($used_year);
Pada script diatas, sql untuk total per rekening kita simpan pada
variabel $sql_total.
1. $sql_triwulan = '
2. SELECT id_rekening
3. , CONCAT("Triwulan ", triwulan) AS triwulan';
4.
5. arsort($used_year);
6. $keys = array_keys($used_year);
7. foreach ($used_year as $key => $year) {
8. $sql_triwulan .= ', target_'. $year .'
9. , realisasi_'. $year .'
10. , ROUND(realisasi_'. $year .'
11. / target_'. $year .'*100, 2) AS
12. persen_'. $year;
13. if ($key < max($keys)) {
14. $sql_triwulan .= ', ROUND ( (realisasi_'.
15. $year .' - realisasi_' . $used_year[$key + 1] . ')
16. / realisasi_' . $used_year[$key + 1] .
17. ' * 100, 2 ) AS growth_'. $year .'';
18.
19. }
20. }
21.
22. $sql_triwulan .= ' FROM pjk_rekening
23. LEFT JOIN (
24. SELECT id_rekening, triwulan';
25. foreach ($used_year as $key => $year) {
26. $sql_triwulan .= ' , SUM(IF(tahun =
27. '.$year.', target, NULL)) AS target_' . $year;
28. $where_sub[] = ' tahun = ' . $year;
29. }
30. $sql_triwulan .= ' FROM pjk_target WHERE ' . join
31. ($where_sub, ' OR ') . ' GROUP BY id_rekening, triwulan';
32.
33. $sql_triwulan .= '
34. ) AS target USING(id_rekening)
35. LEFT JOIN
36. (
37. SELECT id_rekening,
38. CASE WHEN MONTH(tanggal) >= "01"
39. AND MONTH(tanggal) <= "03"
40. THEN 1
41. WHEN MONTH(tanggal) >= "04"
Pada script diatas, sql untuk total per triwulan kita simpan pada
variabel $sql_triwulan
Menampilkan Data…
Selanjutnya kita buat script PHP untuk menampilkan data. Sama
Seperti SQL, tampilan data juga berubah sesuai dengan banyaknya
tahun yang dipilih. Jika tahun yang dipilih lebih dari satu, maka akan
ditampilkan kolom growth pada tahun yang lebih tinggi, jika tahun
yang dipilih hanya satu, maka kolom tersebut tidak ditampilkan.
1. if (isset($_GET['submit'])) {
2. if ($hasil_query)
3. {
4. $thead = '<tr>
5. <th rowspan="2">No</th>
6. <th rowspan="2">Rekening</th>';
7.
8. foreach ($used_year as $key => $year) {
9. $colspan = $key < max($keys) ? ' colspan="5"' : '
10. colspan="4"';
11. $thead .= '<th'.$colspan.'>'. $year .'</th>';
12. }
13.
14. $thead .= '</tr>';
15.
16. foreach ($used_year as $key => $year) {
17. $thead .= '<th>Target</th>
18. <th>Realisasi</th>
19. <th>Pencapaian(%)</th>';
20. if ($key < max($keys)) {
21. $thead .= '<th>Growth(%)</th>';
22. }
23. }
24.
25. echo '
26. <div class="table-responsive">
27. <table>
28. <thead>' . $thead . ' </thead>
29. <tbody>';
30.
31. while($row = mysqli_fetch_assoc($query_triwulan)) {
32. $result_triwulan[$row['id_rekening']][]= $row;
33. }
34.
35. $no = 1;
36. while($row = mysqli_fetch_assoc($query_total)) {
37.
38. echo '<tr class="subtotal">
39. <td>' . $no . '</td>
40. <td>' . $row['nama_rekening'] . '</td>';
41.
42. foreach ($used_year as $key => $year) {
43. echo'<td class="right">' .
44. number_format($row['target_'.$year], 0, ',', '.') . '</td>
45.
Kenapa?
Karena hal ini akan meningkatkan performa baik dari sisi database
maupun aplikasi.