Normalizować, czy nie?

0

Próbuję zamodelować taką sytuację: użytkownicy mogą wskazywać konkretne daty w której są dostępni, ale również dni (wskazanie poniedziałku oznacza, że jest dostępny w każdy poniedziałek). Wymyśliłem więc coś takiego:

create table users
(
  id int4,
  name text NOT NULL
);

create table date_availability
(
  user_id int4 NOT NULL,
  from_time timestamp NOT NULL,
  to_time timestamp NOT NULL
);

create table day_availability
(
  user_id int4 NOT NULL,
  day_of_week int4 NOT NULL,
  from_time time NOT NULL,
  to_time time NOT NULL
);

Teraz, żeby pozyskać listę wszystkich użytkowników dostępnych na mecz, wystarczy takie zapytanie:

/*
DOSTĘPNOŚCI DATOWE
    2023.08.22   19:00 - 21:00 DAMIAN
    
DOSTĘPNOŚCI REKURENCYJNE
	PONIEDZIAŁKI 15:00 - 18:00 DAMIAN
    PONIEDZIAŁKI 16:00 - 20:00 KAROL
    WTORKI       16:00 - 21:00 KAROL
    
MECZ JEST
	2023.08.22   20:00 - 21:00
    
Damian jest dostępny ze względu na dostępność datową, a Karol ze względu na dostępność rekurencyjną
*/

select user_id
from date_availability
where
	from_time <= '2023-08-22 20:00:00'
    and to_time >= '2021-08-22 21:00:00'
union all
select user_id
from day_availability
where
	day_of_week = EXTRACT(dow FROM TIMESTAMP '2023-08-22 20:00:00')
    and from_time <= '2023-08-22 20:00:00'::time
    and to_time >= '2023-08-22 21:00:00'::time

W zasadzie wszystko działa, ale zastanawiam się, czy nie lepiej byłoby zrezygnować z tabeli day_availability i mieć samą date_availability, a w momencie, gdy ktoś definiuje sobie dostępność powtarzalną, to wrzucać do bazy wszystkie możliwe daty (np. na rok w przód). Takie podejście ułatwiłoby np. pobranie listy wszystkich dostępności w ciągu roku. Nie musiałbym generować dat na podstawie dostępności rekurencyjnych. @axelbest zaproponował coś, co ja rozumiem jako nieznormalizowana baza (u mnie jest znormalizowana).

Jak myślicie, które podejście sprawdzi się lepiej?

4

A ja proponowałbym zamodelowanie jednej tabeli, przecież jak ktoś zaznaczy w formularzu że jest dostepny w poniedziałek to zrobisz mu przedział from 2023-08-19 0000 to 2023-08-19 2359. Będzie Ci łatwiej ogarniać zamiast kleić zapytania takie jak wyżej. Bardziej widziałbym to tak:

create table day_availability
(
  user_id int4 NOT NULL,
  day_of_week int4,
  time_from time,
  time_to time,
  recuring int4 NOT NULL //tutaj to zwykly bool
);

I zamiast wybiegać w przód o rok (bo tutaj należy zadać pytanie "a czemu nie na 3 lata wprzód?" - wyciagniesz tylko z SQL'a dzien tygodnia z danej daty i przefiltrujesz to w prosty sposób (hint: będzie potrzebny OR) .

0

@axelbest a to co zaproponowałeś to czasem nie jest odstępstwo od normalizacji? No i jak mam przechować informację o roku, skoro time_from jest o typie time?

0

Tak, nie skupiałem się na tym. A jeśli chcesz przetrzymywać informacje o roku, zamień day_of_week na typ z pełną datą. Będziesz potem musiał troszkę więcej konwertowac, ale przyznaje się że nie skupiłem się na roku w dacie. Bardziej chciałem pokazać że wsadzanie np 60 rekordów na każdy tydzień na dostępność w danym dniu to źle rozwiązanie (5 graczy ma wolne pn,wt,sr, 5 graczy ma cale tygodnie wolne, a 5 graczy ma wolny tylko jeden dzien -> przy skali roku to daje okolo 54* (53 + 57 + 5) rekordów - a to tylko 15 graczy

0

Ale i tak jakoś nie przemawia do mnie podejście łączenia tego w 1 tabelę. Załóżmy, że za jakiś czas pojawi się taki case: określająć dostępność powtarzalną, możemy określić, że np. jesteśmy dostępni co drugi tydzień. Potrzebowalibyśmy wtedy kolejnej kolumny, która byłaby bezużyteczna w przypadku dostępności na konkretną datę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1