Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zliczanie w przelocie, czy zapis do bazy
Forum PHP.pl > Forum > Bazy danych
jsmp
Mam dylemat, jak realizować pewne funkcje statystyczne. Przykładowo codziennie scrapuje sobie kurs waluty. Zapisuje sobie w bazie wg formatu: data | kurs_dnia.

Pytanie, czy np. aby opracować sobie np. średnią przyrostu/spadku z np. 100 pozycji, musiałoby to oznaczać robienie w locie obliczania z surowych danych tego przy każdym wywołaniu witryny. Czy zatem nie lepiej sobie przy zaciąganiu danych od razu powyliczać niektóre dane?

Mam też podobny dylemat jeśli chodzi np. o obliczanie przyrostów dla poszczególnych dni, wtedy ilość operacji była by jeszcze większa - bo dla każdej daty trzeba by było sprawdzić jaki to dzień tygodnia, wyciągnąć wartości osobno dla pon, wt, śr... itd, i dopiero tu zrobić średnią wg dni tygodnia.
ghost1511
Pytasz o to czy od razu pobierać średnią z bazy czy liczyć ją dopiero w php?
jsmp
Nie. To rozumiem, że jest wygodniejsze w zapytaniu. Chodzi mi o sytuację gdy:

2014-02-19 | 321
2014-02-20 | 322
2004-02-21 | 330

I, chce pokazać użytkownikom wzrost pomiędzy wartościami. Mogę to obliczać żywcem biorąc z bazy i lecąc za każdym wywołaniem php wartość(dziś) - wartość (dziś-1), druga opcja to zapisanie tego w taki sposób, żeby przyrost był od razu zapisywany:
2014-02-19 | 321 | -
2014-02-20 | 322 | 1
2004-02-21 | 330 | 8

Taki sam dylemat mam odnośnie kwestii statystycznej, np. chcąc zrobić porównanie wzrostów wg dni tygodnia. Czy lepiej w przelocie sprawdzać jaki dzień tygodnia wynika z daty, czy w nowej kolumnie DB zapisać dzień tygodnia jako 1-7. Ułatwia to selekcję danych potem, stosując WHERE, bez tego niestety za każdym razem musiałbym to ustalać php'em.
phpion
1. Jeżeli dane masz zapisywane dzień po dniu bez luk w dniach to możesz pozostać przy strukturze data, wartość. Wystarczy wówczas, że dołączysz (LEFT JOIN - LEFT by uwzględnić też pierwszy wynik) jeszcze raz tą samą tabelę (pamiętając o aliasie) na warunku (ON) poprzedni.data = biezacy.data - 1 dzien. No i zwykłym odejmowaniem obliczysz różnicę (pamiętając o COALESCE(poprzedni.wartosc, 0) żeby uniknąć NULLi). Jeśli natomiast mogą być luki w datach to nie możesz zrobić opisanego JOINa, bo zapewne chciałbyś uzyskać dane dla dnia poprzedniego zapisanego w bazie (czyli jeśli nie ma danych za wczoraj, to weź z przedwczoraj). Chyba, że miałyby Cię interesować tylko dni poprzednie - wówczas możesz zostać przy JOINie.

2. Dzień tygodnia możesz wyczaić w samym SQL: http://dev.mysql.com/doc/refman/5.5/en/dat...ction_dayofweek
ghost1511
Wydaje mi się że jeżeli chcesz to tylko do warstwy prezentacji (tylko do wyświetlania sekwencji) np do pokazania wykresu to przetrzymywanie tej wartości w bazie nie ma sensu. Natomiast jeżeli chcesz w miarę szybko wyszukiwać po tej wartości np. odszukać wszystkie dni gdzie był spadek/wzrost to może warto byłoby to trzymać. ale osobiście zrobiłbym do tego jakąś osobną tabelę żeby nie zaciemniać sobie obrazu właściwych danych. Dodatkowo musisz pamiętać, że dane z dodatkowej tablicy przestaną być aktualne jeżeli zmienisz coś we właściwych danych. Wtedy należy pamiętać o dwóch update'ach smile.gif


-- edit

Myślę, że mógłbyś jeszcze utworzyć dodatkową kolumnę z identyfikatorem dnia poprzedniego np:

Kod
id_dzien, wartosc, id_dzien_poprzedni
1    10    NULL
2    13    1
3    5    2


id_dzien_poprzedni dać jako klucz obcy (id_dzien) i wtedy możesz sobie łączyć dane zwykłym joinem, liczyć średnie, wyszukiwać dni ze zyskiem/stratą
phpion
Po co ta dodatkowa kolumna? Przecież to wszystko można w SQL policzyć. Fakt, jeśli mogą być luki i istnieje nas poprzedni wpis (niekoniecznie poprzedni dzień) wówczas na pewno przyspieszy to zapytanie zasugerowane przeze mnie. Logiczniejsze dla mnie jednak jest bazowanie na dniu poprzednim, a nie poprzedniej wartości.

PS: Żeby móc JOINować wcale nie trzeba zakładać klucza obcego. W tym przypadku należałoby go jednak założyć, ale z racji integralności danych, a nie możliwości/niemożliwości wykonywania złączeń.
ghost1511
Tak tak smile.gif ja podałem rozwiązanie dla przypadku z lukami w czasie. Tak jest np z kursem walut i szczerze mówiąc domyślam się, że tego dotyczy ten przypadek.
phpion
Ja bym zadbał o to by mieć dane na każdy dzień i zrobił to tak:
  1. CREATE TABLE `test` (
  2. `date` DATE NOT NULL ,
  3. `value` INT NOT NULL ,
  4. PRIMARY KEY (`date`) );
  5.  
  6. INSERT INTO `test` (`date`, `value`) VALUES
  7. ('2014-02-18', 10),
  8. ('2014-02-19', 22),
  9. ('2014-02-20', 31),
  10. ('2014-02-21', 44)
  11. ;
  12.  
  13. SELECT
  14. cur.date,
  15. cur.value,
  16. (CASE WHEN prev.value IS NOT NULL THEN cur.value - prev.value ELSE NULL END) AS diff
  17. FROM
  18. test AS cur
  19. LEFT JOIN test AS prev ON (prev.date = DATE_SUB(cur.date, INTERVAL 1 DAY))
  20. ORDER BY
  21. cur.date ASC
  22. ;
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.