Project: Okul Database · Hub: Okul Database — Reference

Reference: locations Table

Hierarchical Turkish location tree. Self-referential via parent_id.


Table Schema

CREATE TABLE locations (
  id         INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name       VARCHAR(255),
  slug       VARCHAR(255),
  parent_id  INT UNSIGNED NULLABLE,  -- NULL = top-level province
  status     TINYINT DEFAULT 1,
  -- FK: parent_id → locations.id
)

Hierarchy

Level 0: Province (İl)    — parent_id IS NULL
Level 1: District (İlçe)  — parent_id = province.id
Level 2: Neighborhood     — parent_id = district.id (less commonly used)

Key Provinces (Level 0 — parent_id IS NULL)

idnameslugNotes
1İstanbulistanbulLargest city, most schools
2AnkaraankaraCapital
3İzmirizmir
4Antalyaantalya
81 provinces total

Full province list: 81 provinces matching Turkey’s administrative structure. There is NO plate_code column in this table — plate codes (34=İstanbul) are not stored here. Use id for joins.


Sample Districts (Level 1)

idnameslugparent_id
5Arnavutköyarnavutkoy1 (İstanbul)
6Ataşehiratasehir1 (İstanbul)
14Akyurtakyurt2 (Ankara)
16Altındağaltindag2 (Ankara)

How It’s Used

TableColumnLevel
school_filterscity_idProvince (Level 0)
school_filterscounty_idDistrict (Level 1)
schoolscity_idProvince
schoolscounty_idDistrict
customerslocation_level_1Province
customerslocation_level_2District
campuseslocation_idAny level
high_school_pointslocation_level_1, location_level_2Province, District

Geographic Queries

-- Province list (for dropdown / mapping)
SELECT id, name, slug
FROM locations
WHERE parent_id IS NULL AND status = 1
ORDER BY name;
 
-- Districts of İstanbul (id=1)
SELECT id, name, slug
FROM locations
WHERE parent_id = 1 AND status = 1
ORDER BY name;
 
-- School count by province
SELECT l.name as province, COUNT(*) as school_count
FROM school_filters sf
JOIN locations l ON l.id = sf.city_id
WHERE sf.deleted_at IS NULL AND sf.is_active = 1
GROUP BY sf.city_id, l.name
ORDER BY school_count DESC;
 
-- NOTE: school_filters already has city_name and county_name
-- so you often don't need to join locations at all
SELECT city_name, county_name, COUNT(*) as schools
FROM school_filters
WHERE deleted_at IS NULL
GROUP BY city_id, city_name, county_id, county_name;