10 Kesalahan Umum SQL yang Sering Dilakukan Pemula (Dan Cara Memperbaikinya)
Blog/Tips & Trik/10 Kesalahan Umum SQL yang Sering Dilakukan Pemula (Dan Cara Memperbaikinya)

10 Kesalahan Umum SQL yang Sering Dilakukan Pemula (Dan Cara Memperbaikinya)

BimaBima
·16 Desember 2025·14 menit baca

Penulis

Bima

Bima

Founder & Data Professional

Bagikan

Terakhir diperbarui: 22 Desember 2025

TL;DR

Kesalahan paling fatal: lupa WHERE di UPDATE/DELETE. Yang sering: salah urutan clause, NULL handling, Cartesian product. Solusi: selalu test di dev dulu, pake transaction, dan validasi input.

Belajar dari Kesalahan

Semua orang pasti pernah bikin kesalahan waktu belajar SQL. Aku sendiri pernah hampir hapus semua data di production karena lupa WHERE clause. Untung ada backup.

Daripada kamu ngalamin hal yang sama, mending belajar dari kesalahan umum yang sering dilakukan pemula. Di artikel ini, kita bakal bahas 10 kesalahan paling sering beserta cara menghindarinya.

Kesalahan #1: Lupa WHERE di UPDATE/DELETE

Ini kesalahan paling fatal dan paling sering terjadi. Hasilnya? Semua data ke-update atau ke-delete.

Contoh Kesalahan

-- Niat mau update satu customer
UPDATE customers SET status = 'inactive';

-- Yang terjadi: SEMUA customer jadi inactive
-- Niat mau hapus order yang cancelled
DELETE FROM orders;

-- Yang terjadi: SEMUA orders terhapus

Kenapa Ini Terjadi?

Biasanya karena:
- Copy-paste query tapi lupa tambahin WHERE
- Terburu-buru submit query
- Testing di production environment

Cara Mencegah

  1. Selalu tulis WHERE clause dulu
-- Tulis ini dulu
DELETE FROM orders WHERE status = 'cancelled';
-- Baru jalanin kalau udah yakin
  1. Test dengan SELECT dulu
-- Lihat data yang bakal ke-affect
SELECT * FROM orders WHERE status = 'cancelled';

-- Kalau udah bener, baru DELETE
DELETE FROM orders WHERE status = 'cancelled';
  1. Gunakan TRANSACTION
BEGIN;
DELETE FROM orders WHERE status = 'cancelled';
-- Cek hasilnya
SELECT * FROM orders WHERE status = 'cancelled';
-- Kalau bener, COMMIT. Kalau salah, ROLLBACK
COMMIT;  -- atau ROLLBACK;
  1. Enable safe mode di MySQL
SET SQL_SAFE_UPDATES = 1;
-- Sekarang UPDATE/DELETE tanpa WHERE bakal error

Kesalahan #2: Salah Urutan Clause SQL

SQL punya urutan clause yang strict. Salah urutan = error.

Contoh Kesalahan

-- SALAH: HAVING sebelum GROUP BY
SELECT kategori, COUNT(*)
FROM products
HAVING COUNT(*) > 5
GROUP BY kategori;

-- Error: syntax error

Urutan yang Benar

SELECT kolom
FROM tabel
WHERE kondisi_baris
GROUP BY kolom_grouping
HAVING kondisi_agregasi
ORDER BY kolom_urutan
LIMIT jumlah;

Inget urutan ini: S-F-W-G-H-O-L (Select From Where Group Having Order Limit)

Tips Mengingat

Bikin akronim atau cerita:
- "Siti Fatimah Waktu Guru Hadir Order Late"
- Atau: "Selasa Februari Wawan Gi Home Only Learning"

Kesalahan #3: Tidak Menggunakan Alias dengan Benar

Alias bikin query lebih readable, tapi sering salah pakenya.

Contoh Kesalahan

-- SALAH: Pake alias sebelum didefinisiin
SELECT nama, total_order
FROM customers
WHERE total_order > 10;  -- Error! total_order belum ada

-- Karena alias didefinisiin di SELECT, tapi WHERE dieksekusi duluan

Solusi

-- Pake subquery atau CTE
SELECT *
FROM (
    SELECT nama, COUNT(*) as total_order
    FROM customers c
    JOIN orders o ON c.id = o.customer_id
    GROUP BY nama
) AS subq
WHERE total_order > 10;

-- Atau pake HAVING (kalau filter hasil agregasi)
SELECT nama, COUNT(*) as total_order
FROM customers c
JOIN orders o ON c.id = o.customer_id
GROUP BY nama
HAVING COUNT(*) > 10;

Best Practice untuk Alias

-- Kasih alias yang meaningful
SELECT
    c.nama AS nama_customer,  -- Jelas
    COUNT(o.id) AS jumlah_order,  -- Deskriptif
    SUM(o.total) AS total_belanja
FROM customers AS c  -- AS opsional tapi lebih jelas
JOIN orders AS o ON c.id = o.customer_id
GROUP BY c.nama;

Kesalahan #4: Cartesian Product Tanpa Sengaja

Ini terjadi kalau kamu JOIN tabel tanpa kondisi ON yang proper.

Contoh Kesalahan

-- SALAH: Lupa ON clause
SELECT *
FROM customers, orders;

-- Hasil: Setiap customer dipasangkan dengan SETIAP order
-- 100 customers x 1000 orders = 100,000 rows!
-- SALAH: Kondisi JOIN yang salah
SELECT *
FROM customers c
JOIN orders o ON c.nama = o.nama;  -- Harusnya c.id = o.customer_id

Cara Mencegah

  1. Selalu pake explicit JOIN syntax
-- BENAR
SELECT *
FROM customers c
INNER JOIN orders o ON c.id = o.customer_id;
  1. Cek jumlah rows sebelum run query besar
-- Cek dulu estimasi hasilnya
SELECT COUNT(*)
FROM customers c
JOIN orders o ON c.id = o.customer_id;
  1. Pake LIMIT saat testing
SELECT *
FROM customers c
JOIN orders o ON c.id = o.customer_id
LIMIT 10;

Kesalahan #5: NULL Handling yang Salah

NULL di SQL itu tricky. NULL bukan 0, bukan empty string, NULL itu "tidak diketahui".

Contoh Kesalahan

-- SALAH: NULL ga bisa di-compare pake =
SELECT * FROM users WHERE phone = NULL;
-- Hasil: 0 rows (padahal ada yang NULL)

-- SALAH: NULL ga sama dengan empty string
SELECT * FROM users WHERE phone = '';
-- Ini cuma dapet yang empty string, bukan NULL

Cara yang Benar

-- Pake IS NULL atau IS NOT NULL
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;

-- Pake COALESCE untuk default value
SELECT
    nama,
    COALESCE(phone, 'Tidak ada') AS phone
FROM users;

-- Pake NULLIF untuk convert value ke NULL
SELECT NULLIF(phone, '') AS phone FROM users;
-- Empty string jadi NULL

NULL dalam Agregasi

-- COUNT(*) hitung semua rows termasuk NULL
-- COUNT(kolom) skip NULL values
SELECT
    COUNT(*) AS total_rows,
    COUNT(phone) AS yang_punya_phone,
    COUNT(*) - COUNT(phone) AS yang_null
FROM users;

NULL dalam Operasi Matematika

-- Anything + NULL = NULL
SELECT 100 + NULL;  -- Hasil: NULL

-- Gunakan COALESCE
SELECT 100 + COALESCE(discount, 0) FROM products;

Kesalahan #6: Tidak Menggunakan Index

Index bikin query cepat, tapi banyak pemula ga paham pentingnya.

Contoh Masalah

-- Query lambat di tabel besar
SELECT * FROM orders WHERE customer_id = 12345;
-- Full table scan: 1 juta rows di-cek satu-satu

Solusi: Buat Index

-- Buat index di kolom yang sering di-filter
CREATE INDEX idx_orders_customer_id ON orders(customer_id);

-- Sekarang query jadi jauh lebih cepat
SELECT * FROM orders WHERE customer_id = 12345;
-- Index scan: langsung ke data yang relevan

Kapan Perlu Index?

  • Kolom yang sering di-WHERE
  • Kolom yang sering di-JOIN
  • Kolom yang sering di-ORDER BY
  • Kolom dengan high cardinality (banyak unique values)

Kapan Index Malah Buruk?

  • Tabel kecil (< 1000 rows)
  • Kolom yang jarang di-query
  • Kolom yang sering di-UPDATE
  • Kolom dengan low cardinality (cuma beberapa unique values)

Kesalahan #7: SELECT * di Production

SELECT * gampang ditulis tapi banyak masalahnya.

Masalah dengan SELECT *

-- Ambil semua kolom
SELECT * FROM users;
  1. Performance: Ambil data yang ga diperlukan
  2. Network: Transfer data lebih besar
  3. Brittle code: Kalau ada kolom baru, bisa break aplikasi
  4. Security: Mungkin expose data sensitif

Best Practice

-- Sebutin kolom yang dibutuhkan aja
SELECT id, nama, email, created_at
FROM users;

Kapan SELECT * Boleh?

  • Waktu exploring data di development
  • Di subquery (tapi tetep lebih baik explicit)
  • Quick debugging

Kesalahan #8: String Comparison Case Sensitivity

Ini sering bikin bingung karena behavior-nya beda di tiap database.

Contoh Masalah

-- Di PostgreSQL, ini case-sensitive
SELECT * FROM users WHERE nama = 'Budi';
-- Ga akan dapet 'BUDI' atau 'budi'

-- Di MySQL dengan collation default, ini case-insensitive
SELECT * FROM users WHERE nama = 'Budi';
-- Bisa dapet 'BUDI', 'budi', 'BuDi'

Solusi Universal

-- Pake LOWER() atau UPPER() untuk konsistensi
SELECT * FROM users WHERE LOWER(nama) = LOWER('Budi');

-- Atau pake ILIKE di PostgreSQL
SELECT * FROM users WHERE nama ILIKE 'budi';

Best Practice

-- Standardize waktu INSERT
INSERT INTO users (email) VALUES (LOWER('Budi@Email.com'));

-- Atau buat constraint
ALTER TABLE users
ADD CONSTRAINT email_lowercase
CHECK (email = LOWER(email));

Kesalahan #9: Date Format yang Tidak Konsisten

Masalah date format sering bikin query ga jalan atau hasil salah.

Contoh Masalah

-- Format Indonesia: DD-MM-YYYY
-- Format SQL standard: YYYY-MM-DD

-- SALAH: Ini bisa jadi ambigu
SELECT * FROM orders WHERE tanggal = '01-02-2024';
-- Ini 1 Feb atau 2 Jan?

Best Practice

-- Selalu pake ISO format: YYYY-MM-DD
SELECT * FROM orders WHERE tanggal = '2024-02-01';

-- Atau pake explicit conversion
SELECT * FROM orders
WHERE tanggal = TO_DATE('01-02-2024', 'DD-MM-YYYY');

Handling Timezone

-- Simpan dalam UTC
INSERT INTO events (waktu) VALUES (NOW() AT TIME ZONE 'UTC');

-- Convert ke WIB waktu display
SELECT
    waktu AT TIME ZONE 'Asia/Jakarta' AS waktu_wib
FROM events;

Date Comparison

-- SALAH: Ini bisa miss data
SELECT * FROM orders WHERE tanggal = '2024-02-01';
-- Kalau tanggal ada time component, ga akan match

-- BENAR: Pake range
SELECT * FROM orders
WHERE tanggal >= '2024-02-01'
AND tanggal < '2024-02-02';

-- Atau pake DATE()
SELECT * FROM orders
WHERE DATE(tanggal) = '2024-02-01';

Kesalahan #10: Tidak Memvalidasi Input (SQL Injection)

Ini kesalahan keamanan yang serius. SQL injection bisa bikin hacker akses atau hapus data.

Contoh Vulnerable Code

username = request.get('username')
query = f"SELECT * FROM users WHERE username = '{username}'"

Contoh Attack

-- Input malicious:
-- username: '; DROP TABLE users; --

-- Query jadi:
SELECT * FROM users WHERE username = ''; DROP TABLE users; --'
-- Tabel users terhapus!

Cara Mencegah

  1. Pake Parameterized Queries
cursor.execute(
    "SELECT * FROM users WHERE username = %s",
    (username,)
)

session.query(User).filter(User.username == username)
  1. Validasi Input
import re
if not re.match(r'^[a-zA-Z0-9_]+$', username):
    raise ValueError("Invalid username format")
  1. Pake ORM

ORM kayak SQLAlchemy, Django ORM, atau Prisma otomatis handle parameterization.

  1. Principle of Least Privilege

Database user aplikasi jangan dikasih permission DROP TABLE atau DELETE tanpa WHERE.

Bonus: Debugging Tips

1. Baca Error Message dengan Teliti

ERROR: column "nama_lengkap" does not exist
LINE 1: SELECT nama_lengkap FROM users
               ^
HINT: Perhaps you meant to reference the column "nama".

Error message biasanya kasih tau persis di mana masalahnya.

2. Pecah Query Kompleks

-- Query kompleks yang error
SELECT a.*, b.*, c.*
FROM a
JOIN b ON ...
JOIN c ON ...
WHERE ...
GROUP BY ...
HAVING ...

-- Pecah jadi bagian-bagian
SELECT * FROM a LIMIT 5;  -- Test tabel a
SELECT * FROM b LIMIT 5;  -- Test tabel b
SELECT * FROM a JOIN b ON ... LIMIT 5;  -- Test join
-- dst

3. Pake EXPLAIN

EXPLAIN SELECT * FROM orders WHERE customer_id = 123;

-- Lihat apakah pake index atau full scan

4. Cek Data Types

-- Lihat struktur tabel
\d orders  -- PostgreSQL
DESCRIBE orders;  -- MySQL

Kesimpulan

10 kesalahan yang udah kita bahas:

  1. Lupa WHERE di UPDATE/DELETE - Paling fatal, selalu double-check
  2. Salah urutan clause - Inget S-F-W-G-H-O-L
  3. Alias yang salah - Pahami urutan eksekusi SQL
  4. Cartesian product - Selalu pake explicit JOIN dengan ON
  5. NULL handling - Pake IS NULL, bukan = NULL
  6. Tidak pake index - Index kolom yang sering di-filter
  7. SELECT * - Sebutin kolom yang dibutuhkan aja
  8. Case sensitivity - Pake LOWER() untuk konsistensi
  9. Date format - Standarkan ke ISO format YYYY-MM-DD
  10. SQL injection - Pake parameterized queries

Yang paling penting: selalu test di development environment dulu, pake transaction untuk operasi berbahaya, dan backup data secara rutin.

Semoga kamu bisa menghindari kesalahan-kesalahan ini ya! Happy querying!

Bagikan:
Bima
Ditulis oleh

Bima

Founder & Data Professional

Founder Ngulik Data. Passionate about making data analysis accessible for everyone.

Artikel Terkait

SQL vs NoSQL: Perbedaan, Kelebihan, dan Kapan Menggunakannya
Tips & Trik
15 Desember 2025•12 menit baca

SQL vs NoSQL: Perbedaan, Kelebihan, dan Kapan Menggunakannya

Pahami perbedaan SQL dan NoSQL, kelebihan masing-masing, dan kapan waktu yang tepat menggunakannya dengan contoh dari tech companies Indonesia

BimaBima
Kembali ke Blog
Ngulik Data logoNgulik Data

Platform edukasi data lengkap untuk professionals Indonesia. Belajar SQL, Data Analysis, dan lebih banyak lagi dengan praktek langsung dan feedback real-time.

Copyright © 2026 - All rights reserved

LINKS
SupportPricingBlogAffiliates
LEGAL
Terms of servicesPrivacy policy