Veri Tabanı Tasarımı

Pythonla otel rezervasyon programı kodluyorum. Kayıt ekleme , yenileme ve güncelleme gibi konularda bir sorunum yok gayet güzel çalışıyor.

Sorunum: Yeni rezervasyon eklediğimde C-İn ve C-out tarihi olarak iki girdi alıyorum. Bu iki tarih arasında belirli bir odam (örn: 101) dolu olmuş oluyo. Sonrasında belli bir tarih aralığında boş odalarımı görmek istediğimde yada yeni bir kayıt açarken o tarihler arasında aynı odaya başka bir rezervasyon varsa uyarı mesajı verdirtmek istiyorum.
Bir sutuna birden fazla tarih bilgisi girebiliyormuyum.
Nasıl bir yol izlemem gerekiyor. Nasıl bir veri tabanı tasarımı yapmam gerektiğini kafamda oturtamadım. Veri tabanları konusunda çok acemiyim.

Sunucu sürümü: 10.4.24-MariaDB

Bunlarin ikisi de birer query. MariaDB’nin destekleyecegi kadar basit query’ler olmalari lazim. Hizli calistirabilecegi kadar basitler mi bilemiyorum.

Evet de bunu neden yapmak isteyesiniz?

Resme cok detayli bakmadim (bkz: Soru Sorarken Sıkça Düşülen Hatalar #10, #4) ama giris-cikis tarihi yeter gibi duruyor. Yetersiz kaldigi bir yer mi var?

Bunlar ikisinde sorun yok bu iki tarihi ön yüzden çekip rahatça veri tabanına aktarıyorum ama arada kalan tarihlerde sanki oda boşmuş gibi görünüyor yani bu iki tarihin arasındaki tüm tarihleri veri tabanında tutmak istiyorum ki sorgu yaptığımda hangi tarhlerde hangi odaların dolu olduğunu net bir şekilde görebilmem lazım.

Yukarda bahsettiğim sebepten ötürü böyle bir şey istiyorum. Tarihleri str olarak tutabiliyorum fakat ozaman sql sorgusu istediğim gibi çalışmaz. Tarih formatında tutmam gerekiyor sorgu yaparken sorun yaşamamak için. Böyle bir kullanıma örnek bir döküman bulamadım paylaşırsanız işim çok kolaylaşır.

Kodumu yazmaya başlarken böyle bir veri setine ihtiyacım olucağını düşünmüyordum bu yüzden şuanda belki de sorunumu doğru şekilde aktaramıyorum.

En basit tabiriyle ,
elimdekiler : giris tarihi , cikis tarihi, müsteri idsi ve oda no
İstediğim : giris tarihi ve çıkış tarihi arasındaki bütün günler (tarihsel formatda) , müsteri idsi ve oda no

Sorguyu yaparken giriş ve çıkış tarihleri arasındaki tarihleri de otomatik olarak doluymuş gibi gösteremez misiniz?

Örneğin 1. ayın 1’inden 2. ayın 5’ine kadar bir yer tutuldu diyelim. Veri tabanında sadece bu iki veri olacak aynı sizin de yaptığınız gibi. Kullanıcı 1. ayın 15’inin dolu olup olmadığını öğrenmek istediğinde, girdiği tarihin giriş ve çıkış tarihlerinin arasında veya bu tarihlere denk olup olmadığını bir fonksiyon ile belirleyemez misiniz?

Bunu yapmak için giriş ve çıkış tarihleri arasındaki tüm günleri sadece sorgu istenildiği anda hesaplayabilecek bir fonksiyon yazılabilir. Eğer istenen gün bu tarihlerden birine denk ise bu gün rezerve edilemez çıktısını veremez misiniz?

Bu tarz konulara pek hakim değilim, sadece algoritma kurmayı denemeye çalışıyorum.

  1. Array olarak tutabilirsiniz: PostgreSQL: Documentation: 16: 8.15. Arrays

  2. Veya semayi normalize edip baska bir tabloya tasabilirsiniz:

ad | soyad | tarih_id

tarih_id | tarih

Her tarih_id’ye tekabul eden bir suru tarih olur.

  1. Sorguyu < ve > ile yapabilirsiniz. Boylece aradaki gereksiz tarihleri tutmaniza gerek kalmaz.

  2. Veya tarihleri baslangic+bitis olarak tutan yukaridaki tablodan, sanki herkes tek gun kaliyormus gibi tek tarih kolonuna sahip olan bir view olusturabilirsiniz.

  3. Bambaska bir opsiyon da, ilgili tarih araligini tek bir query ile alip bos gunleri kod tarafinda hesaplamak.


Yukarida yazdiklarimin cogu icin basit SQL ozelliklerine ihtiyaciniz var, o yuzden bir SQL veritabani sistemi kullanmak isteyebilirsiniz: Neden MySQL kullanmamaliyim? Yerine ne kullanabilirim? [PostgreSQL]

Edit: Tavsiyeleri numaraladim

Merhabalar, tarih verilerini veritabanında string olarak değil de belli bir saat dilimindeki bir timestamp olarak saklasak ve query yaparken belirtilen tarihlerin timestamplarının odanın tutulduğu timestampların aralığında mı diye kontrol etsek çok daha mantıklı olmaz mı? Bir odanın tutulan tarih aralığını bir string array olarak tutmak bana mantıksız geldi açıkçası.

String olarak tutmak son derece mantiksiz, evet, ozellikle de DATE veya TIMESTAMP WITH TIME ZONE gibi turler varken. Fakat gorebildigim kadariyla kimse string’den bahsetmemis zaten?

Giris ve cikis tarihlerini tutup aralik hesabi yapmak yukarida sundugum 3. opsiyon. Sifirdan tasarlanan bir sistem icin muhtemelen en dogrusu ve her halukarda en esnek olani (4 ve 5 ile birlikte), fakat ayni zamanda en cok is gucu gerektireni. (CHECK constraint’ini kafadan yazabilir misiniz, mesela?) Uygunlugu hakkinda bir sey soylemek zor o yuzden, ozellikle de soru array kolonlarina dogrudan deginiyorken.

Bu yöntem aklıma yattı fakat sorgu aşamasında çok mu karmaşa yaratır diye endişeliyim.

Burada nasıl bir yöntem önerdiğinizi anlayamadım.

Timestamp bir tarih aralığını mı tutuyor ? Örnek olarak nasıl bir girdi alıyor ?
Çok cahilce sorular soruyorsam üzgünüm biryandan araştırıyorum ama ilk kez sql ile çalışıyorum ve projeye başlarken işin veri tabanı tarafını fazla hafife almışım.

Yaratmaz, zira SQL tam olarak bu tur sorgular icin tasarlanmis bir dil.
Mumkunse sadece baslangic ve bitis zamani tutan opsiyonlardan biri yatsin ama.

Sadece giris ve cikis zamanlarini tutmak:

Fonksiyonlara dikkatlice bakarsaniz iki tarih araliginin birbiriyle kesismesini donduren bir tanesini bile gorebilirsiniz.

Projede zaten ilerlediyseniz yukarida sundugum 5. opsiyonu goz ardi etmeyin. Bir suru proje, turlu sebeplerden dolayi, database’i “aptal” depo alani olarak kullanip butun is mantigini kod uzerinde yurutuyor.

def oda_k(giris_t,cikis_t):
	
	def time_range(dt1: dt, dt2: dt):
		if dt2 > dt1:
			return [
				(dt1 + td(days=i)).strftime("%Y.%m.%d") 
				for i in range((dt2 - dt1).days)
			]
		elif dt1 > dt2:
			return [
				(dt2 + td(days=i)).strftime("%Y.%m.%d") 
				for i in range((dt1 - dt2).days)
			]
	gr=giris_t.replace("-",".")
	ck=cikis_t.replace("-",".")
	dt1 = dt.strptime(f"{gr}", "%Y.%m.%d")
	dt2 = dt.strptime(f"{ck}", "%Y.%m.%d")
	tarihler=time_range(dt1,dt2)

	sr=""
	sr=sr.replace(".","-")
	for i in tarihler:
		sr= sr + f"  '{i}'NOT  BETWEEN giris_t AND cikis_t OR"
	baglanti.execute(f"""
	SELECT oda_no FROM hepsi
	WHERE
	(
		{sr[0:-2]}

	
	)
	""")

	hepsi = baglanti.fetchall()

	json1=json.dumps(hepsi, indent=4, sort_keys=True, default=str,ensure_ascii=False)
	json1=json.loads(json1)
	print(json1)
	b_odalar=[]
	for i in json1:
		b_odalar.append(i["oda_no"])
	return b_odalar

Şuan böyle bir kod yazdım iki tarih arasındaki tarhileri alıp sql sorgusu yapıyor ve bos odaları gösteriyor.İşe yarıyor gibi görünüyo ama tam olarak anlamak için koduma entegre edicem biraz deneme yapıcam.Kodumdaki diğer bütün fonksiyonlar zaten çalışır durumda sadece biraz daha örnek data girişi yapmam lazım.

Epey bi ilerledim aslında ama değişiklik yapmaktan çekinmem sil baştan bile yazabilirim zamanım çok.
Benzeri bir program için benden yıllık 10.000 tl para istediler bende kendim yazmaya karar verdim. Hem kendimi geliştirmiş olucam hemde işimi yaparken kullandığım programı daha iyi tanır ve geliştirmeler yapabilirim diye düşünüyorum.

Kodu calistirmadan ne yaptigini gormek zor, ama BETWEEN (<= ve >=) kullandiginizi goruyorum. OVERLAPS kullanmayi denesenize?

Nasıl çalıştığını bilmiyorum araştırıcam şuanki kodum çalışıyor ama eğer daha kullanışlı ise değiştirebilirim.
Veri tabanını değiştirmeden bu işi sorgu teknikleriyle halletmek çok iyi oldu çok teşekkür ederim.

örneğin 20-06-2023 | 23-06-2023 tarihleri arasında bir rezervasyonum var. bu tarihler arasında oda dolu gösterilecek. ben olsam başka bir tablo oluşturup burada reservation_id (ss’deki tablodan alınan id’nin foreignkey’i olarak) tutabilirim, ayrıca bu tabloya 20-06-2023, 21-06-2023, 22-06-2023, 23-06-2023 tarihlerini ayrı ayrı aynı reservation_id ile tutarım. odanın dolu olup olmadığına bu tablodan bakarım sanırım