Ben bu sistemi ağaç mantığı ile açıklamak istiyorum bundan 3 sene önce araştırmadan keşfettiğim daha sonra bazı makalelerde karşılaştığım bir yapıdan bahsedeceğim. Bu örnek biraz basit olabilir ama geliştirmek sizin zihinsel gücünüze kalmıştır.
Genelde eticaret sitelerinde kategori ağacının kaç dal olacağı bilinmez bazen 2 dal bazen 5 dal bunu bilemeyiz. Ağaç sistemi ile bu işi çözmek kolay benim DNA adı verdiğim bu sistem kategorileri tek bir tabloda toplayarak belirli bir alanda kategorinin atası dediğim ilk kategorinin ID numarasından başlayarak bir üst ve kendi ID si olmak üzere bir DNA zinciri oluşturuyorum ne diyor bu diyebilirsiniz :) Şimdi konuyu biraz açacağım ve daha iyi anlayacağınızı umuyorum.
KATEGORILER adında basit bir tablomuzun var olduğunu düşünelim ve bu tablo içindeki alanlarımız
Id
Adi
UstId
Dna
Durum
olsun
Ana kategori eklerken sql Sorgumuz
|
|
Dikkat ederseniz Dna alanına 0 girdim bu ilk insan :)
Şimdi bunun çocuğu dediğimiz ve bundan kalıtım almış kategoriyi yaratalım
|
|
Dna alanına dikkat edersek 0,1,2 olduğunu göreceğiz burada 0 ana sayfa için kullanılacak 1 Bilgisayar kategorisinin Id si ve 2 de kendi Id numarası bu kodlama 0,1,2 kalıtım olarak Masaüstü kategorisinin nerden geldiğini belirtti.
Şimdi Masaüstü kategorisinin çocuğunu ve Bilgisayar kategorisinin torununu oluşturalım.
|
|
Dna da X Model kategorisinin soyağacını görmemiz mümkün.
sağdan sola okursak 3 kendi 2 masaüstü 1 bilgisayar olarak kalıtımı görebiliyoruz.
Şimdi bu kategorinin altına bir kategori daha eklersek.
|
|
Y Modelin Dnasını sağdan sola okursak 4 kendisi, 3 X Model, 2 Masaüstü, 1 Bilgisayar, 0 anasayfamız.
Bu mantık yardımı ile sınırsız kategori sistemi oluşturabilirsiniz.
İyi çalışmalar dilerim.
önceki yazı Php ile basit bir zaman ayarı |
sonraki yazı Güldüren Programlama Dilleri |
Bu konuda aşağıdaki iyi makaleyi okumanızı öneririm.
http://www.gokceyalcin.com/mysql-hiyerarsik-veriler-kategori
http://www.gokceyalcin.com/mysql-ile-hiyerarsik-veriler-ikinci-bolum-ic-ice-yerlesim-kalibi
(orjinali http://dev.mysql.com/tech-resources/articles/hierarchical-data.html)
Konu kesinlikle çok önem verilmesi gereken bir konu ve düzgün yapılandırılmadığı zaman bir çok web sitesini dize getirebilecek darboğazlara neden olabilir.
bu konuda bir de kodaman yazısı vardı:
veritabanı programlayamama yazıları (nested setler)
http://www.kodaman.org/yazi/asp-net-ado-net-treeview
arkadaşlar için yararlı olabilir... yazı için teşekkürler
normalizasyonun dibine vurmuşsunuz :)
Bu şekilde bende bi deneme yapmıştım ilerleyen aşamada sıkıntı yaratması çok olası yalnız , INNER JOIN ile yapmak kargaşanın önüne geçebilir diye düşünüyorum
Daha iyi çözümler üretilebilir, bu şekilde işi uzatmış olursunuz. Normalde bu işlem için "ParentID" adında bir kolon daha açılır, eğer kategorinin bir üst kategorisi varsa, parentid bölümüne, üst kategorinin id si girilir (adjacency list model), böylece sonsuz bir hiyerarşi sağlanabilir.
parentid ve id bölümleri integer olduğundan, rahatlıkla sql tarafında da işleme sokulabilir, inner join yapılabilir..
peki örneğin bilgisayar kategorisine tıkladığımda onun en altındaki kategoriye ait olan ürünleride listeleyeceğim. böyle bir durumda birçok connection açmak zorunda kalcaksın. bu savunduğun, bahsettiğimden önceki kullandığım sistemdi.
@trampfd kesinlikle katılıyorum. bahsettiğin yöntem sanıyorum ki tüm profesyonellerin kullandığı sistemdir. şimdilik en iyi çözüm o olsa gerek..
infoman, ben connection açıp kapamıyorum.
Sualine şöyle cevap verebilirim, bilgisayar kategorisine tıkladığında onun en altındaki alt kategoriye ait ürünleri listelemek istediğini söylemişsin, "en alt" gibi bir kavram, bu örnekteki dinamik yapıda zaten olamaz. Onu sağlamak için kategoriler için bir kolon daha açıp sıra bilgisini tutman gerekir (ben "order" isimli sayısal değer tutan bir alan kullanıyorum sıralama için) neyse.
Mantıken "Bilgisayar" isimli kategori ile işlem yapacaksan, o kategoriye bağlı alt kategorilerden istediğinin ürünlerini zaten sorguda belirterek çekebilirsin, sıralama olarak en alttakine bağlı ürünleri istiyorsan onu da yukarıda belirttiğim kategorinin "order" değerini koşul belirterek tek seferde çekebilirsin, bunlar sql tarafında halledilebilecek işler.
Bana soracak olursanız, tavsiyem kategori sistemini projenin kodlama kısmında halledin. Zaten çok spesifik olmayan bir projede milyonlarca kategori ve alt kategori olmayacağı için, tümünü tek seferde çekip, ram üzerinden kullanmak daha mantıklı olur, sonuçta trace edildiğinde tek sorgu ve 1-2kb lık data akışı olduğunu görürsünüz. Daha fazla performans isterseniz de stored procedure veya view kullanabilirsiniz, ve kategorilerin her saniye güncellenmediğini düşünürsek cache de kullanılır, ki dahada ötesi zaten olmaz.
Öncelikle bu saatte tam uyuyacakken bu sayfanın linkini atıp beni huzursuz ettiği için trampfd'ye saygılarımı sunarım.
Bir ana kategorinin alt kategorisi varsa, bu alt kategorinin de onlarca hiyerarşik alt kategorisi varsa ne olacak? O halde onlarca tablo mu açmak gerekiyor hiyerarşi oluşturmak için? Bu şunun altındaydı.Yok bu da bunun altındaydı.Şu da onun altındaydı... Uzar gider bu iş..
Bence şu yapılmalı.Bir tablo oluşturulur.ID özelliğine auto increment kaydedilir.MySQL'in yapacağı işi php ile birkerede yaptırırsınız.Sonuçta kategoriler içerisindeki yazı veya üründen çok olamayacak.Sınırlı sayıda olacak.Max 100 diyelim..
ID - KatID - AltID
Sütunlarına sahip bir tablo oluşturursunuz.Kategori eklerken de örneğin;
Haber
- Güncel
-- Spor
şeklinde kategori açacaksanız önce haber kısmını ana kategori olarak işaretleyip database'e yazdırırsınız.Daha sonra Güncel kategorisini açarken alt kategori diyerek açarsınız.Alt kategori dediğiniz anda php ile 2 kez veri girişi yaparsınız.Eğer 2. alt kategoriyse bu eklediğiniz.2 kez kontrol eder.Şöyle ki;
ID - KatID - AltID
1 Haber
2 Haber Güncel
3 Güncel Spor
4 Haber Magazin
5 Magazin Güzeller
Spor kategorisine tıklandığında AltID sütununda Spor olanı bulup, üst kategorisi var mı bakarsınız.Varsa (-ki yoksa sorgu kısalmış olur) üst kategorisini AltID'de sorgulayıp bir üst kategorisini bulursunuz.Bunu tek bir SQL komutu ile yapmak gayet mümkündür.Eklediğiniz içerik ne ise, siteden ona tıkladığınızda verinin KatID ve AltID sütunlarındaki 2 veriye de bakarak kolayca kategorilerini ve varsa üst ve alt kategorilerini de yazdırabilirsiniz.Kategorileri yazdırırken de önce AltID'si boş olanları yazdırıp mysql fetch assoc sorgusuyla bir while ile gayet güzel tüm kategorileri altına yazdırabilirsiniz.
Sql sorgusunda sıkıntı çekiyorsanız for ile function içinde tek birkez kullanabilir, hatta sürekli kategori oluşturmuyorsanız çıktıları loglayıp direkt yazdırabilirsiniz.O derece..
İyi seyirler..
Bilal.
sorunumuz en uçtakileri listelerken birçok connection açmamaksa, kategoriler için adjacency bir yapı kurulu -ki benim tercih ettiğim yapı çoğu zaman budur -, ürün kaydederken de, her ürünün her kademedeki kategorisi için bir tabloya ürün id, kategori id ve kademe şeklinde bir kayıt yazdırın. tek sql ile bir ana, ara ya da alt kategorideki tüm ürünleri listelersiniz.
aynı yapı kateogori mantığına da uygulanabilir. normalizasyon derecenize göre uygun kodlama yaptığınız sürece, bazı temel kurallara sadık kaldığınızda çok sorun yaşamazsınız.
temelde bu tip yapılar için, veri sık güncellenmez, verinin elde edilmesi sıklığı fazladır. örneğin bir kategori 3-5 kez güncelleme işlemine tabi tutulurken, milyonlarca kez select edilebilir. aynı şekilde bir ürün birkaç kez update edilir, belki daha sık bir şekilde fiyatı güncellenir, ancak ürünün listelenmesi yine milyonları bulabilir.
bu durumda insert/update işlemlerinin çok sayıda ve yavaş olması çok sorun teşkil etmez, önemli olan ürünü listelerken (select) olabilecek en hızlı şekilde listelemektir. tabii ki insert/update işlemleri de makul seviyelerde olmalı, ancak select işlemini hızlandırmak için insert/update zamanından feda edilebilir.
bu bilgiler ışığında, yukarıda bahsettiğim yapı kategoriler için pek ala kullanılabilir.
kategori id, üst kategori id, kademe
gibi bir yapıya kaydedilip, örnek olarak;
Haber
- Güncel
-- Spor
--- Futbol
--- Basketbol
-- Ekonomi
--- Para
--- Borsa
- Dünya
-- AB
gibi ağacımızda kategori tablomuz,
kategori id, kategori adı
1 Haber
2 Güncel
3 Spor
4 Futbol
5 Basketbol
6 Ekonomi
7 Para
8 Borsa
9 Dünya
10 AB
olursa aralarındaki ilişki tablosu
kategori id, üst kategori id, kademe
2 1 1
3 1 1
3 2 2
4 1 1
4 2 2
4 3 3
5 1 1
5 2 2
5 3 3
6 1 1
6 2 2
7 1 1
7 2 2
7 6 3
8 1 1
8 2 2
8 6 3
9 1 1
10 1 1
10 9 2
gibi bir ilişki tablosuna ulaşırız. buradan güncel kategorisinin altında yer alan tüm verileri çekmek istersek üst kategori id'si 2 olanları select etmemiz
yeterli olacaktır.
benzer manıkta, ürünlerin kategorilerini de tutabiliriz. onun için de
yazi, kategori id, kademe
şeklinde bir tabloda tutarak, örneğin para ile ilgili bir yazı girildiğini varsayarsak (id'si 78 olsun),
78 7 4
78 6 3
78 2 2
78 1 1
şeklinde 4 kayıt eklenmesi yeterlidir.
bu yazı ile ilgili tüm kategorilere ve kategori hiyerarşisine yine tek select ile ulaşabildik. aslında biz bu sonuncu veri setine kategori ilişki tablomuzdan erişebiliriz, ancak amacımız daha hızlı erişmek olduğundan bu şekilde kayıt ile de erişebiliriz. tercihli olarak kullanılabilir.
pek kullanışlı bulmadım açıkçası. trampfd söylediği teknik oldukça kullanışlı bence
Harika bir yapı ancak normalde en sık kullanılan yapı
pk int
KategoriAd varchar(30)
UstID int (veya altID)
ancak bu sizin ilan karma bir ilan.
bence cok saçma diyenler size bir soru
İkinci el ilan siteniz var diyelim
Bilgisayar
--Tasinabilir
----Notebook
------notebook aksesuar
----Netbook
------Netbook Aksesuar
--Masaustu
Kitap
-- Bilişim - Bilgisayar
-- Sağlık - Beslenme
gibi bir yapını var normalde mantık gereği Bilgisayar kategorisine bakıyorsanız onun altındaki tüm kategorilerdeki ürünleri görmek istersiniz. ancak normalde kullanılan en üstteki mantıkta bu sistem çatlıyor cünki
select * from urunler Where KategoriID = 2 (bilgisyarın kategorisi no)
dediğinizde netbook ve notebook masaustu vs onlar gelmez ancak bu dna yapısı ile bu sorunu aşabilirsiniz. ben bu yapıyı çözmeye neredeyse 15 gündür uğrasıyorumdum makale ile dna ve genel kullanılan ı birleştirmek aklıma gelmemişti. bu makale ile çözdüm. "evreka" "evreka" :)
@absconder'in yöntemini kullanın.
bu arada normalizasyon gerçekten önemli bir konu bu konuda duyarlı olduğun için tebrik ederim absconder.
mahoni üzülerek söylüyorum ki yaptigin yöntem yanlis.
tabloları parçalara ayır
ilişkileri kur, kod tarafında bir sorgu ile kategorileri dataset e at
foreach ile hiyerarşiyi oluştur hepsi bir birini görür dna yapısı malesef yanlış bir yöntem.
normalizasyon ile ne alakası var hocam genel önerilen yapı
KategoriID KategoriAd USTID
simdi bu yapı zaten benim örneğimde var ek bir kolon olarak da DNA kolonu var
yani recursive ile sorunsuz ben hiyararsiyi sağlıyorum UstID den yararlanarak
ancak join ile birlestirip bir kategorinin ürünlerini ararken KategoriId ye göre değilde
create proc spKategoriyeGoreUrunGetir
@KatID int
as
Declare @DNA varchar(50)
Select @DNA=DNA from kategori where KategoriID=@KatID
select * from Urunler u
join Kategori k on k.KategoriID= u.KategoriID
where k.Dna like @param + '%'
burda bilgisayar kategorisi
1 bilgisayar 0.1
3 Tasınabilir 0.1.3
12 notebook 0.1.3.12
gibi kategoriyapısı var ben bilgisayar ın ürünlerini getirmek için menüden bilgisayar linkine tıkladı bilgisayar
linki calıstı querystring ile 1 değerini aldık 2 sorgu calıstırıyorum
1 - 1 nolu kategorinin DNA sını öğreniyorum
2 - urunler tablosu ile kategoriler tablosunu birlestirip DNAsında 1 nolu kaydın dna değerini içeren urunleri getiriyorum
alternatif olarak wordpress in kullandığı coklu kategori yapısı ile de bu durum çözülebilir nasıl yapılır bir
KategoriID KategoriAd USTID tablosu olur
urun de bir kolon acılmaz onun yerine ek bir tabloda birlestirilir
BirlesimTablosu
PK_ID int
KategoriID int
UrunID int
böylece bir ürün birden fazla kategori de olabildiği için artık admin panelinde ürünü eklerken programatik olarak ust kategorilerne de eklemeniz gerekiyor
yani notebooka eklendiğinde tasınabilire de pc ye de eklenmesi lazım.
her yiğidin bir yoğurt yemesi var kim nasıl istiyorsa öyle yapsın.
Herkese merhaba :)
Konuyla ilgili ben de bir şeyler yazmak istedim.
Makalemde geçen kodları, MS SQL SERVER 2008 veritabanında kullandım, veri tabanı ile işlemleri de C# ile yazdığım AlmostromFrameWork kütüphanem ile yaptım.

Tablomuza 1 adet ana kategori ekleyelim :
using (AlmostromFrameWork.DataAccessLayer.MSSQL Db = new AlmostromFrameWork.DataAccessLayer.MSSQL(Global.ConnectionString))
{
using (SqlCommand Cmd = Db.CreateCommand("KategoriEkle"))
{
Cmd.Parameters.Add("@IdNo", SqlDbType.Int).Value = 0;
Cmd.Parameters.Add("@KategoriAdi", SqlDbType.NVarChar).Value = 'Elektronik';
Cmd.ExecuteNonQuery();
Cmd.Parameters.Clear();
}
}
Dikkat ederseniz ana kategorileri eklerden @IdNo parametresinin değerini 0 olarak gönderiyoruz.
Tablomuza eklediğimiz Elektronik kategorisinin alt kategorilerini eklerken , elektronik kategorisinin Id değerini yani şuanki değeri olan 8'i , parametre olarak gönderdiğimiz @IdNo ya ekliyoruz. :
using (AlmostromFrameWork.DataAccessLayer.MSSQL Db = new AlmostromFrameWork.DataAccessLayer.MSSQL(Global.ConnectionString))
{
using (SqlCommand Cmd = Db.CreateCommand("KategoriEkle"))
{
Cmd.Parameters.Add("@IdNo", SqlDbType.Int).Value = 8;
Cmd.Parameters.Add("@KategoriAdi", SqlDbType.NVarChar).Value = 'Telefonlar';
Cmd.ExecuteNonQuery();
Cmd.Parameters.Clear();
}
}
Aynı mantıkla istediğimiz kadar alt kategori ekliyoruz.
Şimdi sadece ana kategorileri istediğimizde sorgumuz ve çıktımız aşağıdaki gibidir :
SELECT [Id],[KategoriAdi] FROM [Kategoriler] WHERE [IdNo]=0


Elektronik / Telefonlar / seçildiğini farzedersek sorgumuz ve çıktımız aşağıdaki gibidir :
SELECT [Id],[KategoriAdi] FROM [Kategoriler] WHERE [IdNo]=9
Elektronik / Telefonlar / Motorola / seçildiğini farzedersek sorgumuz ve çıktımız aşağıdaki gibidir :
SELECT [Id],[KategoriAdi] FROM [Kategoriler] WHERE [IdNo]=21
pillinetwork sitelerine yorum ekleyebilmek ve daha fazlası için, üye olun ya da giriş yapın.
Nokta ve pilli ortak yapımı olan kodaman.org hep birlikte içerik üretip gelirini yazarları ile paylaştığımız kolektif bir kod yazarları blogudur. Siz de katılabilirsiniz.