Mieć 2 stoły:„Instytucje” i „Obszary”
Zezwól „Obszarom” na linkowanie do siebie, tj. identyfikator_obszaru, identyfikator_obszaru_rodzica
W ten sposób zawsze łączysz instytucję z identyfikatorem obszaru, a wewnętrzna logika może określić, czy obszar ten jest uważany za dzielnicę, czy za miasto.
Więc teraz masz
institutions (
id UNSIGNED INT NOT NULL PK AI,
area_id UNSIGNED INT NOT NULL,
name VARCHAR NOT NULL
)
i
areas (
id UNSIGNED INT NOT NULL PK AI,
parent_area_id UNSIGNED INT NOT NULL DEFAULT 0,
name VARCHAR NOT NULL,
type ENUM('city','district') NOT NULL DEFAULT 'city'
)
Pole area.type jest opcjonalne, ale jeśli chcesz je zdefiniować jako takie, może to być sposób na zrobienie tego w bazie danych (w przeciwnym razie po prostu załóż, że jeśli parent_area_id =0, to jest to miasto, w przeciwnym razie jest to dzielnica)
W ten sposób podczas wybierania pola wszystko, co robisz, to
SELECT *
FROM institutions
INNER JOIN areas
ON areas.id = institutions.area_id
Możesz być w 100% pewien, do której strony linkuje instytucja area_id, nie ma znaku zapytania, czy przejść do tabeli Dzielnice czy Miasta, na pewno jest to tabela obszarów, która z kolei traktuje Dzielnice i Miasta w ten sam sposób i przedstawia informacje w format, który Twój interfejs może następnie zinterpretować jako miasto lub dzielnicę. Opcjonalnie możesz pójść o krok dalej, jeśli naprawdę chcesz
SELECT
i.*,
COALESCE(a_parent.id,a_child.id) AS city_id,
COALESCE(a_parent.name,a_child.name) AS city_name
FROM institutions AS i
INNER JOIN areas AS a_child
ON a_child.id = i.area_id
LEFT JOIN areas AS a_parent
ON a_parent.id = a_child.parent_area_id
To na przykład zawsze zwróci nazwę miasta, nawet jeśli instytucja jest powiązana z określoną dzielnicą w mieście