Cikkek

Hatékony adatbázis tervezés társasházkezeléshez

📅 2025. június 29. |
👨‍💻 Adatbázis tervezés, SQL Server, Társasházkezelés
#SQL #AdatbázisTervezés #Társasházkezelés #AuditTrail #RelációsAdatbázis

A társasházkezelés egyik legnagyobb kihívása a tulajdonosi változások pontos nyomon követése. Egy jól megtervezett adatbázis struktúra nemcsak a jelenlegi állapotot rögzíti, hanem teljes audit trail-t biztosít minden változásról. Ebben a cikkben bemutatom, hogyan építsünk fel egy olyan adatbázist, amely rugalmasan kezeli a tulajdonosi változásokat és lehetővé teszi az időbeli lekérdezéseket.

 

⚠️ A hagyományos megközelítés problémái

A legtöbb társasházkezelő rendszer egyszerű kapcsolótáblákkal oldja meg a tulajdonos-albetét kapcsolatot:

— Hagyományos megközelítés (problémás)
CREATE TABLE Albetetek (
AlbetetID INT PRIMARY KEY,
Albetet_Jel NVARCHAR(50),
TulajdonosID INT, — Közvetlen kapcsolat
Alapterulet_m2 DECIMAL(10,2)
);

Ez a megközelítés problémái:

  • Nincs változástörténet
  • Tulajdonosváltás = adatvesztés
  • Nem követhető, ki mikor volt tulajdonos
  • Vízóra beépítés/eltávolítás nem rögzített

🏗️ A javasolt három táblás architektúra

1. Albetetek tábla – A fizikai ingatlan adatok

CREATE TABLE [dbo].[Albetetek] (
[AlbetetID] INT IDENTITY(1,1) PRIMARY KEY,
[TarsashazID] INT NOT NULL,
[Albetet_Jel] NVARCHAR(50) NOT NULL,
[Alapterulet_m2] DECIMAL(10,2) NOT NULL,
[Tulajdoni_Hanyad] DECIMAL(18,6) NOT NULL,
[Vizora] BIT NOT NULL DEFAULT 0,
[Tarolo_db] INT NOT NULL DEFAULT 0,
[Fo_szam] INT NOT NULL DEFAULT 1,
[Megjegyzesek] NVARCHAR(500),
[Letrehozva] DATETIME2 DEFAULT GETDATE()
);

Fontos: Ez a tábla NEM tartalmaz tulajdonosi adatot! Csak az albetét fizikai jellemzőit rögzíti.

Miért jó ez így?

  • Tiszta adatmodell – egy tábla, egy felelősség
  • Stabil alapadatok – ritkán változó információk
  • Normalizált struktúra – nincs redundancia

2. Tulajdonosok tábla – Személyes adatok

CREATE TABLE [dbo].[Tulajdonosok] (
[TulajdonosId] INT IDENTITY(1,1) PRIMARY KEY,
[TarsashazID] INT NOT NULL,
[Nev] NVARCHAR(255) NOT NULL,
[Email] NVARCHAR(255),
[Telefonszam] NVARCHAR(50),
[Cim] NVARCHAR(500),
[Adoazonosito] NVARCHAR(20),
[Bankszamlaszam] NVARCHAR(50),
[Aktiv] BIT DEFAULT 1,
[Letrehozva] DATETIME2 DEFAULT GETDATE()
);

🔑 Kulcspontok:

  • 🏠 TarsashazID alapú szeparáció – minden társasház független
  • 👤 Nincs albetét referencia – tiszta tulajdonosi adatok
  • 📧 Elérhetőségi információk – kommunikációhoz szükséges adatok

3. Tulajdonosi_Valtozasok tábla – A kapcsolat és audit trail

CREATE TABLE [dbo].[Tulajdonosi_Valtozasok] (
[ID] INT IDENTITY(1,1) PRIMARY KEY,
[AlbetetID] INT NOT NULL,
[Valtozas_datuma] DATETIME2 NOT NULL DEFAULT GETDATE(),
[Valtozas_tipusa] NVARCHAR(100) NOT NULL,
[Regi_ertek] NVARCHAR(255),
[Uj_ertek] NVARCHAR(255),
[RegiTulajdonosID] INT,
[UjTulajdonosID] INT,
[Visszaterites_osszege] DECIMAL(15,2),
[Potlolag_fizetendo] DECIMAL(15,2),
[Megjegyzes] NVARCHAR(1000),
[LetrehozasDatuma] DATETIME2 DEFAULT GETDATE(),

CONSTRAINT FK_Valtozasok_Albetet
FOREIGN KEY (AlbetetID) REFERENCES Albetetek(AlbetetID),
CONSTRAINT FK_Valtozasok_RegiTulajdonos
FOREIGN KEY (RegiTulajdonosID) REFERENCES Tulajdonosok(TulajdonosId),
CONSTRAINT FK_Valtozasok_UjTulajdonos
FOREIGN KEY (UjTulajdonosID) REFERENCES Tulajdonosok(TulajdonosId)
);

💡 Gyakorlati példák a rugalmasságra

Tulajdonosváltás rögzítése

— Kovács János eladja az albetétet Nagy Péternek
INSERT INTO Tulajdonosi_Valtozasok (
AlbetetID,
Valtozas_tipusa,
RegiTulajdonosID,
UjTulajdonosID,
Megjegyzes
) VALUES (
15,
‘Tulajdonosváltás’,
123, — Kovács János
456, — Nagy Péter
‘Adásvételi szerződés alapján’
);

Vízóra beépítése

— Vízóra beépítése az I.15 albetétbe
INSERT INTO Tulajdonosi_Valtozasok (
AlbetetID,
Valtozas_tipusa,
Regi_ertek,
Uj_ertek,
UjTulajdonosID,
Megjegyzes
) VALUES (
15,
‘Vízóra beépítés’,
‘0’, — Korábban víz nélküli
‘1’, — Most vízórás
456, — Jelenlegi tulajdonos
‘Vízmérő felszerelés 2024.03.15’
);

Tároló hozzáadása

— Új tároló vásárlás
INSERT INTO Tulajdonosi_Valtozasok (
AlbetetID,
Valtozas_tipusa,
Regi_ertek,
Uj_ertek,
UjTulajdonosID,
Potlolag_fizetendo
) VALUES (
15,
‘Tároló vásárlás’,
‘0’,
‘1’,
456,
250000 — Tároló ára
);

🔍 Intelligens lekérdezések

Aktuális tulajdonos meghatározása

— Ki a tulajdonosa az I.15 albetétnek jelenleg?
SELECT
a.Albetet_Jel,
t.Nev as AktualisTulajdonos,
t.Email,
tv.Valtozas_datuma as UtolsoValtozas
FROM Albetetek a
INNER JOIN (
SELECT
AlbetetID,
UjTulajdonosID,
ROW_NUMBER() OVER (
PARTITION BY AlbetetID
ORDER BY Valtozas_datuma DESC
) as rn
FROM Tulajdonosi_Valtozasok
WHERE UjTulajdonosID IS NOT NULL
) tv ON a.AlbetetID = tv.AlbetetID AND tv.rn = 1
INNER JOIN Tulajdonosok t ON tv.UjTulajdonosID = t.TulajdonosId
WHERE a.Albetet_Jel = ‘I.15’;

Tulajdonosi történet lekérdezése

— I.15 albetét teljes tulajdonosi története
SELECT
tv.Valtozas_datuma,
tv.Valtozas_tipusa,
t_regi.Nev as RegiTulajdonos,
t_uj.Nev as UjTulajdonos,
tv.Megjegyzes
FROM Tulajdonosi_Valtozasok tv
LEFT JOIN Tulajdonosok t_regi ON tv.RegiTulajdonosID = t_regi.TulajdonosId
LEFT JOIN Tulajdonosok t_uj ON tv.UjTulajdonosID = t_uj.TulajdonosId
INNER JOIN Albetetek a ON tv.AlbetetID = a.AlbetetID
WHERE a.Albetet_Jel = ‘I.15’
ORDER BY tv.Valtozas_datuma DESC;

Vízóra változások követése

— Albetétek vízmérő státusz változásai
SELECT
a.Albetet_Jel,
tv.Valtozas_datuma,
CASE tv.Uj_ertek
WHEN ‘1’ THEN ‘Vízórás’
WHEN ‘0’ THEN ‘Víz nélküli’
ELSE ‘Ismeretlen’
END as UjStatusz,
t.Nev as Tulajdonos
FROM Tulajdonosi_Valtozasok tv
INNER JOIN Albetetek a ON tv.AlbetetID = a.AlbetetID
INNER JOIN Tulajdonosok t ON tv.UjTulajdonosID = t.TulajdonosId
WHERE tv.Valtozas_tipusa LIKE ‘%vízóra%’
ORDER BY tv.Valtozas_datuma DESC;

💼 Üzleti előnyök

📊 1. Teljes átláthatóság

  • Bármely időpontra rekonstruálható a tulajdonosi struktúra
  • Tulajdonosváltások gyakoriságának elemzése
  • Vitás esetek tisztázása dokumentált történet alapján

🤖 2. Automatizálható folyamatok

  • Tulajdonosváltáskor automatikus egyenlegátvezetés
  • Email értesítések változásokról
  • Költségmegosztás automatikus újraszámítása

🌐 3. Külső integráció lehetőségek

  • Tulajdonosi portál – webes hozzáférés saját adatokhoz
  • Mobil alkalmazás – egyenleg lekérdezés, befizetések
  • Hatósági jelentések – automatikus adatszolgáltatás

4. Megfelelőségi követelmények

  • GDPR compliance – pontos adattörlés és módosítás
  • Audit trail – minden változás dokumentált
  • Adatbiztonság – szerepkör alapú hozzáférés

⚙️ Implementációs tippek

1. Indexelés stratégia

— Kritikus indexek a teljesítményért
CREATE INDEX IX_Valtozasok_AlbetetID_Datum
ON Tulajdonosi_Valtozasok (AlbetetID, Valtozas_datuma DESC);

CREATE INDEX IX_Valtozasok_UjTulajdonos
ON Tulajdonosi_Valtozasok (UjTulajdonosID);

2. Adatintegritás biztosítása

— Trigger a konzisztencia fenntartására
CREATE TRIGGER tr_TulajdonosiValtozas_Check
ON Tulajdonosi_Valtozasok
AFTER INSERT
AS
BEGIN
— Ellenőrzés: UjTulajdonosID és AlbetetID ugyanabban a társasházban van-e
IF EXISTS (
SELECT 1 FROM inserted i
INNER JOIN Albetetek a ON i.AlbetetID = a.AlbetetID
INNER JOIN Tulajdonosok t ON i.UjTulajdonosID = t.TulajdonosId
WHERE a.TarsashazID != t.TarsashazID
)
BEGIN
RAISERROR(‘Tulajdonos és albetét különböző társasházban!’, 16, 1);
ROLLBACK;
END
END

3. Performance optimalizálás

— Materialized view az aktuális tulajdonosokhoz
CREATE VIEW v_AktualisTulajdonosok
WITH SCHEMABINDING
AS
SELECT
a.AlbetetID,
a.Albetet_Jel,
t.TulajdonosId,
t.Nev,
tv.Valtozas_datuma
FROM dbo.Albetetek a
INNER JOIN (
SELECT
AlbetetID,
UjTulajdonosID,
Valtozas_datuma,
ROW_NUMBER() OVER (
PARTITION BY AlbetetID
ORDER BY Valtozas_datuma DESC
) as rn
FROM dbo.Tulajdonosi_Valtozasok
WHERE UjTulajdonosID IS NOT NULL
) tv ON a.AlbetetID = tv.AlbetetID AND tv.rn = 1
INNER JOIN dbo.Tulajdonosok t ON tv.UjTulajdonosID = t.TulajdonosId;

📈 Gyakorlati használati esetek

Használati esetHagyományos módszerÚj architektúraElőny
TulajdonosváltásTulajdonosID frissítéseÚj rekord a változások táblábanTörténet megőrzése
Vízóra beépítésAlbetetek tábla módosításaVáltozás rögzítése dátummalKi, mikor, miért dokumentálva
Tároló vásárlásTarolo_db oszlop növeléseVáltozás + pénzügyi következményekTeljes üzleti folyamat
Hatósági ellenőrzésJelenlegi állapotBármely időpont rekonstruálhatóCompliance biztosítása

🚀 Továbbfejlesztési lehetőségek

🔮 Jövőbeli funkciók

  • Machine Learning – Tulajdonosváltási trendek előrejelzése
  • API integráció – Ingatlan.com, otthonterkep.hu kapcsolat
  • Blockchain audit – Megváltoztathatatlan változáslög
  • IoT integráció – Okos vízmérők automatikus leolvasása

Minta JSON API válasz

{
“albetet”: {
“id”: 15,
“jel”: “I.15”,
“alapterulet”: 65.5,
“aktualis_tulajdonos”: {
“nev”: “Nagy Péter”,
“email”: “nagy.peter@email.com”,
“telefon”: “+36301234567”
},
“jellemzok”: {
“vizora”: true,
“tarolo_db”: 1,
“fo_szam”: 2
},
“tulajdonosi_tortenrt”: [
{
“datum”: “2024-03-15”,
“tipus”: “Tulajdonosváltás”,
“regi_tulajdonos”: “Kovács János”,
“uj_tulajdonos”: “Nagy Péter”
},
{
“datum”: “2024-02-10”,
“tipus”: “Vízóra beépítés”,
“regi_ertek”: “0”,
“uj_ertek”: “1”
}
]
}
}

📊 Összegzés

A bemutatott három táblás architektúra jelentős előnyöket biztosít:

  • 🎯 Tiszta adatmodell – minden tábla egyértelmű felelősséggel
  • 📚 Teljes audit trail – minden változás nyomon követhető
  • 🔄 Rugalmas módosítások – új változástípusok könnyen hozzáadhatók
  • Optimalizálható teljesítmény – intelligens indexelés és view-k
  • 🌐 Integrációs lehetőségek – modern webes és mobil alkalmazásokhoz

Ez a megközelítés nemcsak a jelenlegi igényeket elégíti ki, hanem jövőálló alapot teremt egy professzionális társasházkezelő rendszer számára.

💡 Implementációs javaslatok

  1. Fokozatos bevezetés – Kezdj egy kisebb társasházzal
  2. Adatmigrálás – Készíts alapos migrációs tervet
  3. Felhasználói képzés – Mutasd be az új lehetőségeket
  4. Monitorozás – Figyeld a teljesítményt és használhatóságot
  5. Dokumentáció – Készíts részletes használati útmutatót