Founding rate: RM5 off Basic, forever — applied automatically. See pricing

Menu

Harga

Percuma untuk mula. RM 25/bulan untuk seluruh bank.

Cancel bila-bila masa — kebanyakan orang subscribe untuk satu hiring cycle, bukan selamanya.

Free

RM 0

  • 46 soalan SQL percuma merentasi setiap tahap kesukaran
  • Semua 29 bab lesson SQL, dengan playground yang boleh dijalankan
  • Keseluruhan track Excel — 15 bab dan graded practice
  • Practice dan grading tanpa had — tiada apa yang bermasa
  • AI coach, 3 sesi/hari — baca query sebenar anda dan bagitahu apa yang salah, tak pernah bagi jawapan
Cuba yang pertama, tak perlu log masuk →

Sprint

RM 49

Bayaran sekali sahaja, akses Basic penuh selama 90 hari — tiada subscription, tiada apa untuk cancel

Bulanan

RM 25RM 20/mo

kadar founding, digunakan automatik semasa checkout, terkunci selagi anda kekal subscribe — tiada kod untuk ditaip

atau
— RM 194/tahun, jimat RM 46 berbanding bulanan

Cancel bila-bila masa dari akaun anda — tiada e-mel, tiada panggilan telefon.

Semua yang ada dalam Basic

  • Track Data Analyst, dari awal sampai habis — Basic buka semua level yang locked, bukan setakat free preview
  • AI coach pada 30 sesi/hari — selesaikan sebanyak mungkin query yang anda stuck dalam satu sesi tanpa terhad
  • Free bagi jawapan. Basic ajar sebab — dan tanya soalan kedua, yang interview sebenar tanya seterusnya.
  • Dashboard dan review queue yang makin berguna semakin lama anda guna laman ini — kategori terlemah, apa nak practice seterusnya, apa yang anda salah dan tak pernah balik semula
  • Keseluruhan bank soalan terbuka, plus take-home round — setiap soalan SEA dan global-MNC, setiap pek yang locked, solution dan grading termasuk
  • Data Lab (beta) — query performance pada warehouse ~300,000 baris, tiada practice site lain pergi lebih dari beberapa baris. Masih dalam pembinaan dan akan jadi Pro, termasuk percuma dengan Basic sehingga siap dibina — akses tamat bila beta tamat
  • Soalan dan lesson baharu setiap minggu, free dan paid sama — subscribe sekali dan setiap release akan datang sudah termasuk
Pelajar sepenuh masa? Dapatkan Basic pada RM 12/bulan →

Ini maksud "ajar sebab"

Satu walkthrough penuh, tak dipendekkan — bukan preview.

Setiap soalan Basic datang dengan walkthrough berbentuk begini: cubaan pertama yang salah bentuk, sebab ia salah, dan reasoning yang bawa dari situ ke jawapan sebenar.

Grab · aggregation

Completed rides by city

Grab's operations team wants to know how many completed rides happened in each city.

From the rides table, return the city and the number of completed rides (status = 'completed') as completed_rides, for every city that has at least one completed ride.

Step 1: Filter before you count

SELECT id, city, status FROM rides WHERE status = 'completed' ORDER BY city, id;
idcitystatus
6Johor Bahrucompleted
7Johor Bahrucompleted
8Johor Bahrucompleted
1Kuala Lumpurcompleted
2Kuala Lumpurcompleted
4Penangcompleted

Nine rides in, six out. The three cancellations — including Ipoh's only ride — are gone before anything is counted. Ipoh dropping out entirely is not an accident to fix later; it's the correct answer to "every city that has at least one completed ride."

Step 2: Group the survivors and count

SELECT city, COUNT(*) AS completed_rides
FROM rides
WHERE status = 'completed'
GROUP BY city;
citycompleted_rides
Johor Bahru3
Kuala Lumpur2
Penang1

GROUP BY city folds the six rows into three buckets; COUNT(*) runs once inside each bucket.

Step 3: Why WHERE and not HAVING

Both filter, but they run at different times. WHERE runs before grouping, on individual rows. HAVING runs after, on the groups — so it can only see things that survived aggregation.

A row-level condition like status = 'completed' belongs in WHERE. A group-level one like "only cities with 3 or more completed rides" belongs in HAVING, because the count doesn't exist until the groups do. See Query execution order and HAVING.

Step 4: The two wrong answers

Dropping the filter. No error, four rows, and every single number is wrong:

SELECT city, COUNT(*) AS completed_rides FROM rides GROUP BY city;
citycompleted_rides
Ipoh1
Johor Bahru3
Kuala Lumpur3
Penang2

Johor Bahru still reads 3, which is right by coincidence — all three of its rides completed. That coincidence is what lets this mistake survive a glance.

Moving the filter inside the aggregate. Postgres supports FILTER, and it counts correctly, but it changes which cities appear:

SELECT city, COUNT(*) FILTER (WHERE status = 'completed') AS completed_rides
FROM rides
GROUP BY city;
citycompleted_rides
Ipoh0
Johor Bahru3
Kuala Lumpur2
Penang1

The three real counts match — but Ipoh is back with a zero, because grouping happened before the filter and Ipoh's cancelled ride was still there to make a group. That's the whole difference between the two clauses: WHERE decides which rows exist, FILTER only decides what gets counted. Neither is wrong in general; here the prompt asks for cities with at least one completed ride, so WHERE is the one that answers the question.

Cuba sendiri →

Siapa di sebalik ini

mahir_data dibina dan dijalankan oleh seorang engineer, secara terbuka, untuk pasaran hiring SEA yang jadi tema — senario gaya Grab, Shopee, Maybank, bukan table textbook generik. Soalan dan lesson baharu ship setiap minggu.

FAQ

Apa jadi bila saya cancel?
Plan anda kembali ke free pada akhir billing period semasa — anda kekal ada akses kepada semua yang Basic buka sehingga itu, dan semua yang free selepas itu.
Perlu install apa-apa tak?
Tak. Setiap soalan jalan terhadap Postgres engine sebenar (PGlite) dalam browser anda — tak perlu sign up untuk cuba, tiada apa dihantar ke server untuk grade satu query.
SQL saya dihantar ke server?
Hanya jika anda minta feedback dari AI coach. Menjalankan dan grading query berlaku sepenuhnya client-side; teks query anda tak pernah tinggalkan browser melainkan anda klik "Ask the coach."
Anda terus tambah soalan?
Ya — soalan dan lesson baharu ship pada kadar mingguan, free dan paid sama, dan apa-apa yang ditambah selepas anda subscribe termasuk tanpa kos tambahan.