Idenya
Sejauh ini setiap kolom yang kamu tampilkan sudah ada di tabel. Pertanyaan sungguhan butuh nilai yang dihitung: keuntungan per produk, harga dengan pajak, label lengkap yang dibuat dari dua kolom. SQL menghitungnya saat itu juga, baris demi baris, seperti formula yang kamu seret ke bawah di kolom spreadsheet.
Dan kadang kamu sama sekali tidak menginginkan setiap baris, hanya nilai-nilai yang berbeda: "di kota mana saja pelanggan kita tinggal?" Itulah DISTINCT.
DISTINCT: nilai unik
Tim penjualan ingin tahu di kota mana saja pelangganmu tinggal, mungkin untuk merencanakan ke mana pengiriman berikutnya. Kalau kamu hanya memilih kolom kota, kamu mendapat satu baris per pelanggan, jadi kota yang punya beberapa pelanggan muncul beberapa kali:
SELECT city
FROM customers;
city
------------
Jakarta
Bandung
Surabaya
Jakarta
Yogyakarta
Medan
NULL
Surabaya
Denpasar
Semarang
Jakarta
Makassar
(12 rows)
Jakarta muncul tiga kali. Tambahkan DISTINCT untuk menyimpan setiap nilai sekali saja:
SELECT DISTINCT city
FROM customers
ORDER BY city;
city
------------
Bandung
Denpasar
Jakarta
Makassar
Medan
Semarang
Surabaya
Yogyakarta
NULL
(9 rows)
NULL (kota Gita yang tidak diketahui) juga dianggap sebuah nilai oleh DISTINCT, jadi ia muncul sekali, diurutkan terakhir.
Dengan beberapa kolom, DISTINCT menyimpan setiap kombinasi yang unik:
SELECT DISTINCT status, channel
FROM orders
ORDER BY status, channel;
status | channel
-----------+---------
cancelled | app
cancelled | web
completed | app
completed | web
pending | web
shipped | web
(6 rows)
Itu cara cepat untuk melihat kombinasi mana yang benar-benar terjadi di datamu, langkah pertama yang sangat umum saat menjelajahi sebuah tabel.
Menghitung kolom
Berapa keuntungan toko dari setiap produk? Itu harga dikurangi biaya membeli produknya, dan tidak ada tabel yang punya kolom untuk itu. Kamu bisa menulis perhitungannya langsung di daftar SELECT, dan database menghitungnya untuk setiap baris:
SELECT name, price, cost, price - cost
FROM products
LIMIT 4;
name | price | cost | ?column?
----------------------+--------+--------+----------
French Press 600ml | 185000 | 110000 | 75000
Pour-over Kettle | 320000 | 210000 | 110000
Arabica Gayo 250g | 95000 | 52000 | 43000
Robusta Lampung 250g | 65000 | 35000 | 30000
(4 rows)
Kolom barunya bernama ?column?, yang tidak berguna di laporan. Beri nama dengan AS:
SELECT name, price, cost, price - cost AS margin
FROM products
ORDER BY margin DESC
LIMIT 4;
name | price | cost | margin
------------------+--------+--------+--------
USB-C Hub | 289000 | 170000 | 119000
Pour-over Kettle | 320000 | 210000 | 110000
Desk Lamp LED | 245000 | 140000 | 105000
Wireless Mouse | 175000 | 98000 | 77000
(4 rows)
Nama setelah AS disebut alias. Perhatikan bahwa ORDER BY bisa memakainya, karena pengurutan terjadi setelah SELECT. (WHERE tidak bisa memakainya, karena WHERE berjalan sebelum SELECT. Modul alias membahas ini.)
Operator-operator yang biasa bisa dipakai: +, -, *, /, dan % untuk sisa bagi. Urutan matematika standar berlaku, jadi pakai tanda kurung supaya jelas.
Jebakan pembagian integer
Ini jebakan yang menjerat hampir semua orang setidaknya sekali. Ajukan pertanyaan sederhana ke PostgreSQL, berapa 7 dibagi 2:
SELECT 7 / 2 AS result;
result
--------
3
(1 row)
Saat kedua angka adalah bilangan bulat (integer), PostgreSQL melakukan pembagian integer dan membuang desimalnya. Jebakan ini merusak perhitungan persentase:
SELECT name, (price - cost) / price * 100 AS margin_pct
FROM products
LIMIT 3;
name | margin_pct
--------------------+------------
French Press 600ml | 0
Pour-over Kettle | 0
Arabica Gayo 250g | 0
(3 rows)
Setiap margin bernilai nol, karena (185000 - 110000) / 185000 adalah 0 dalam hitungan integer. Perbaikannya: jadikan salah satu angka desimal. Menulis 100.0 alih-alih 100 dan mengalikan lebih dulu menyelesaikannya:
SELECT name, (price - cost) * 100.0 / price AS margin_pct
FROM products
LIMIT 3;
name | margin_pct
--------------------+---------------------
French Press 600ml | 40.5405405405405405
Pour-over Kettle | 34.3750000000000000
Arabica Gayo 250g | 45.2631578947368421
(3 rows)
Sekarang hitungannya benar, tapi tidak ada yang mau enam belas angka desimal. ROUND(value, digits) merapikannya:
SELECT name, ROUND((price - cost) * 100.0 / price, 1) AS margin_pct
FROM products
ORDER BY margin_pct DESC, name
LIMIT 5;
name | margin_pct
--------------------+------------
Gel Pen Set | 60.5
Ceramic Mug | 60.0
Notebook A5 Dotted | 60.0
Scented Candle | 60.0
Bamboo Plant | 58.3
(5 rows)
Setiap kali kamu membagi di SQL, tanyakan "apakah kedua sisinya integer?" Kalau ya, tulis salah satunya sebagai desimal (100.0) atau konversi dengan ::numeric, misalnya price::numeric / 3.
Menyambung teks
Kadang kamu ingin satu label yang enak dibaca, bukan kolom-kolom terpisah, seperti "French Press 600ml (Kitchen)" untuk daftar produk. || merekatkan potongan-potongan teks satu demi satu. Apa pun yang ingin kamu taruh di antaranya, seperti spasi dan tanda kurung di sini, ditulis sebagai teks dalam kutip tunggal:
SELECT name || ' (' || category || ')' AS label
FROM products
LIMIT 3;
label
------------------------------
French Press 600ml (Kitchen)
Pour-over Kettle (Kitchen)
Arabica Gayo 250g (Coffee)
(3 rows)
NULL menyebar lewat perhitungan
Perhitungan apa pun yang melibatkan NULL menghasilkan NULL, karena "tidak diketahui ditambah apa pun" tetap tidak diketahui:
SELECT name, price * stock AS stock_value
FROM products
WHERE category = 'Home';
name | stock_value
----------------+-------------
Scented Candle | 6750000
Throw Pillow | 4800000
Bamboo Plant | NULL
(3 rows)
Stok Bamboo Plant tidak diketahui, jadi nilai stoknya juga tidak diketahui. Itulah jawaban yang jujur. Kamu akan belajar mengganti NULL dengan nilai default di modul NULL.
Mengapa ini penting untuk kode bersih
Menghitung di SQL menjaga logikanya di dekat datanya: satu query memberi semua orang margin yang sama, alih-alih lima orang masing-masing membangun formulanya sendiri di Excel. Beri setiap kolom hasil perhitungan alias yang jelas (margin_pct, bukan x), dan bersikaplah sengaja soal pembagian. Nama yang jelas dan tipe yang benar adalah yang membuat sebuah query menjadi sumber kebenaran yang bisa diandalkan.
Rangkuman
DISTINCTmembuang baris duplikat; dengan beberapa kolom, ia menyimpan kombinasi yang unik.- Perhitungan di
SELECTberjalan untuk setiap baris; beri nama denganAS alias. ORDER BYbisa memakai alias;WHEREtidak bisa.- Integer ÷ integer membuang desimal: pakai
100.0atau::numeric. ROUND(x, n)membulatkan kendesimal;||menyambung teks.- Perhitungan apa pun dengan NULL menghasilkan NULL.