DataLens

DISTINCT dan ekspresi dasar

Buang baris duplikat, hitung kolom baru seperti margin keuntungan, dan hindari jebakan pembagian integer.

Level: Dasar · 12 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

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)
Ide utama

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

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Berikutnya: Fungsi agregat (COUNT, SUM, AVG) →