Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

2 Stron V   1 2 >  
Reply to this topicStart new topic
> Obliczanie średniej i odchylenia standardowego
damianprz
post
Post #1





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


(IMG:http://images48.fotosik.pl/188/36eb6354103b063bm.jpg)
SCREEN

Na screenie widać prosty schemat tabeli w bazie danych
Na dole struktura a na górze rekordy
Mamy 8 dni i 4 produkty dla których trzeba policzyć Popyt średni i Odchylenie Standardowe

Kolega proponuje tak obliczać Pśr i OS
Cytat("Norbert")
$pytanko="SELECT popyt_klej FROM popyt";
$rezultat = mysql_query($pytanko)
or die("Błąd zapytania");


$tablica = mysql_fetch_array($rezultat);
$n=count($tablica);
$srednia=0;

for($i=0;$i<=$n;$i++)
{
$srednia=$srednia+$tablica[$i];
}

$srednia=$srednia/$n;

for($i=0;$i<=$n;$i++)
{
$wyraz_srednia=$tablica[$i]-$srednia; // tutaj do zmiennej $wyraz_srednia przypisujesz roznice danej liczby i sredniej wszystkich liczb

$tablica2[$i]= $wyraz_srednia * $wyraz_srednia;
}

for($i=0;$i<=$n;$i++)
{
$wynik=$wynik+$tablica2[$i]; //dostajesz sume tych wszystkich kwadratow roznicy wyrazu i sredniej;
}
$wynik=sqrt($wynik);

echo "<h1>Srednia: ".$srednia."</h1><P>";
echo "<h1>Odchylenie: ".$wynik."</h1><P>";


Kod daje takie wyniki dla popyt_klej i popyt_srubki
Srednia: 10
Odchylenie: 17.320508075689

Kod daje takie wyniki dla popyt_farba i popyt_drewno
Srednia: 5
Odchylenie: 8.6602540378444

Powinna wyjść średnia dla popyt_klej:
160/8 czyli 20

Mam takie pytanie: Czy da radę napisać tak kod aby później była możliwość dodawania kolejnych wierszy Id=9, data, popyty dla poszczególnych towarów itd... oraz możliwość dodawania towarów, czyli chodzi mi o taki kod który by liczył Pśr i OS nawet gdy tabela będzie się rozrastać w 2 wymiarach

Chyba nie ma sensu dla każdego towaru robić osobną tabelę w bazie danych. Takie rozwiązanie jakie prezentuje screen, że w jednej tabeli są wszystkie towary i wszystkie wartości popytu jest chyba najlepszy. Tylko problem z tym ciężkim do wymyślenia kodem.

Jakby ktoś był w stanie coś wymyśleć to proszę o jakieś pomysły lub kontakt
GG 3257134
Go to the top of the page
+Quote Post
outsider
post
Post #2





Grupa: Zarejestrowani
Postów: 267
Pomógł: 36
Dołączył: 8.08.2008

Ostrzeżenie: (0%)
-----


przy obliczaniu sredniej zmien znak <= na < :

  1. for($i=0;$i<$n;$i++)
  2. {
  3. $srednia=$srednia+$tablica[$i];
  4. }


Go to the top of the page
+Quote Post
damianprz
post
Post #3





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


I co to da?
Próbowałem i nic

Powyższy kod bierze tylko wartości z Id=1 i dzieli przez n=2
i dlatego wychodzą wyniki odpowiednio 5 10 10 5 bo w tym wierszu wartości wynoszą 10 20 20 10

Id Data popyt_drewno popyt_srubki popyt_klej popyt_farba
1 2009-07-01 10 20 20 10

Nawet nie wiem jak policzyć średnią z tych ośmiu wartości dla danego towaru a co dopiero mówić o kodzie który będzie liczył wszystko nawet pod dodaniu wierszy czy kolumn

Pomocy!

$tablica = mysql_fetch_array($rezultat);

tu jest problem bo to polecenie wczytuje tylko 1 wiersz
Czy jest polecenie aby wczytać do $tablica całą tablicę

Id Data popyt_drewno popyt_srubki popyt_klej popyt_farba
1 2009-07-01 10 20 20 10
2 2009-07-02 15 25 15 20
3 2009-07-03 5 15 25 5
4 2009-07-06 10 5 15 35
5 2009-07-07 5 15 25 15
6 2009-07-08 10 10 10 10
7 2009-07-09 15 15 25 25
8 2009-07-10 15 15 25 25

Go to the top of the page
+Quote Post
thek
post
Post #4





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Wartość średnia to prosta sprawa, robisz bowiem sumowanie wszystkich wartości w kolumnie i dzielisz przez liczbę wierszy.Najlepiej chyba będzie wykonać 2 zapytania. Pierwsze zwróci sumy każdej kolumny. Drugie zwróć liczbę wierszy w tabeli. To da nam średnią (IMG:style_emoticons/default/smile.gif)
Z odchyleniem standardowym gorzej... To pierwiastek z sumy kwadratów wartości rekordów podzielonych przez liczbę wierszy od których odjęto kwadrat średniej arytmetycznej. Najszybciej więc będzie zrobić coś podobnego do poprzedniego. Ale teraz nie tylko będziemy sumowali wartości rekordów, tylko wpierw je podniesiemy do kwadratu. Zwróconą sumę podzielimy przez liczbę rekordów i odejmiemy od tego kwadrat wyliczonej średniej. Całość zaś spierwiastkujemy (IMG:style_emoticons/default/smile.gif)
Za chwilkę zrobię tabelkę i sprawdzę swoje rozumowanie (IMG:style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
damianprz
post
Post #5





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Tylko jak zrobić
sumowanie wszystkich wartości w kolumnie

W ogóle to taki kod

$pytanko="SELECT * FROM popyt";
$rezultat = mysql_query($pytanko)
or die("Błąd zapytania");
$tablica = mysql_fetch_array($rezultat);
$n=count($tablica);
$wiersze = mysql_num_rows($rezultat);
var_dump($tablica) ;


daje następujące wyniki:

array(12) { [0]=> string(1) "1" ["Id"]=> string(1) "1" [1]=> string(10) "2009-07-01" ["Data"]=> string(10) "2009-07-01" [2]=> string(2) "10" ["popyt_drewno"]=> string(2) "10" [3]=> string(2) "20" ["popyt_srubki"]=> string(2) "20" [4]=> string(2) "20" ["popyt_klej"]=> string(2) "20" [5]=> string(2) "10" ["popyt_farba"]=> string(2) "10" }
var dump pokazuje że tablica jest jednowymiarowa, wczytało tylko pierwszy wiersz ten z Id=1

wiersze: 8
z kolei funkcja mysql_num_rows mówi że w tabeli jest 8 wierszów, jak dla mnie var dump zaprzecza mysql_num_rows
n: 12
zliczone elementy tablicy, dlaczego tylko 12? tyle ile pokazuje var dump

Natomiast taki kod:
echo "<h1>TAb0: ".$tablica[0]."</h1><P>";
echo "<h1>TAb1: ".$tablica[1]."</h1><P>";
echo "<h1>TAb2: ".$tablica[2]."</h1><P>";
echo "<h1>TAb3: ".$tablica[3]."</h1><P>";
echo "<h1>TAb 0 0: ".$tablica[0][0]."</h1><P>";
echo "<h1>TAb 0 1: ".$tablica[0][1]."</h1><P>";
echo "<h1>TAb 1 0: ".$tablica[1][0]."</h1><P>";
echo "<h1>TAb 1 1: ".$tablica[1][1]."</h1><P>";
echo "<h1>TAb 0 2: ".$tablica[0][2]."</h1><P>";
echo "<h1>TAb 2 0: ".$tablica[2][0]."</h1><P>";
echo "<h1>TAb 2 1: ".$tablica[2][1]."</h1><P>";
echo "<h1>TAb 1 2: ".$tablica[1][2]."</h1><P>";
echo "<h1>TAb 2 2: ".$tablica[2][2]."</h1><P>";
echo "<h1>TAb 3 0: ".$tablica[3][0]."</h1><P>";
echo "<h1>TAb 3 1: ".$tablica[3][1]."</h1><P>";
echo "<h1>TAb 3 2: ".$tablica[3][2]."</h1><P>";
echo "<h1>TAb 3 3: ".$tablica[3][3]."</h1><P>";
echo "<h1>TAb 0 3: ".$tablica[0][3]."</h1><P>";
echo "<h1>TAb 1 3: ".$tablica[1][3]."</h1><P>";
echo "<h1>TAb 2 3: ".$tablica[2][3]."</h1><P>";


daje wyniki:

TAb0: 1

TAb1: 2009-07-01

TAb2: 10

TAb3: 20


czyli tutaj mamy kolejne komórki 1. wiersza (Id=1)

TAb 0 0: 1

TAb 0 1:

TAb 1 0: 2

TAb 1 1: 0

TAb 0 2:

TAb 2 0: 1

TAb 2 1: 0

TAb 1 2: 0

TAb 2 2:

TAb 3 0: 2

TAb 3 1: 0

TAb 3 2:

TAb 3 3:

TAb 0 3:

TAb 1 3: 9

TAb 2 3:


Nie wiem o co tu chodzi, komórka [0][0] ma wartość 1, niektóre komórki nie mają wartości, komórka [1][3] ma wartość 9 ((IMG:style_emoticons/default/questionmark.gif) )

Ten post edytował damianprz 26.08.2009, 22:22:57
Go to the top of the page
+Quote Post
thek
post
Post #6





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Sumowanie wszystkiego w kolumnie:
  1. SELECT sum(popyt_drewno) AS suma_dr, sum(popyt_srubki) AS suma_sr, sum(popyt_klej) AS suma_kl, sum(popyt_farba) AS suma_fa FROM tablica_danych

Sumowanie kwadratów w kolumnie:
  1. SELECT sum(pow(popyt_drewno, 2)) AS kw_dr, sum(pow(popyt_srubki, 2)) AS kw_sr, sum(pow(popyt_klej, 2)) AS kw_kl, sum(pow(popyt_farba, 2)) AS kw_fa FROM tablica_danych

Brakuje Ci jedynie liczby wierszy (IMG:style_emoticons/default/winksmiley.jpg)
  1. SELECT count(id) AS ile FROM tablica_danych

A więc ostatecznie:
  1. $sumy = mysql_fetch_row( mysql_query( "SELECT sum(popyt_drewno) AS suma_dr, sum(popyt_srubki) AS suma_sr, sum(popyt_klej) AS suma_kl, sum(popyt_farba) AS suma_fa FROM tablica_danych" ) );
  2. $kwadraty = mysql_fetch_row( mysql_query( "SELECT sum(pow(popyt_drewno, 2)) AS kw_dr, sum(pow(popyt_srubki, 2)) AS kw_sr, sum(pow(popyt_klej, 2)) AS kw_kl, sum(pow(popyt_farba, 2)) AS kw_fa FROM tablica_danych" ) );
  3. $temp = mysql_fetch_array( mysql_query( "SELECT count(id) AS ile FROM tablica_danych" ) );
  4. $liczba = $temp['ile'];
  5. for($i = 0; $i < 4; $i++) {
  6. $srednia = $sumy[$i]/$liczba;
  7. $odchylenie = sqrt( ($kwadraty[$i]/$liczba ) - pow( $srednia, 2 ) );
  8. echo 'Średnia wynosi: '.$srednia.', a odchylenie: '.$odchylenie
  9. }

Nie dałem jedynie sprawdzenia czy $result zwraca wynik z bazy czy nie. To i tak chyba tylko na localhoscie będzie odpalane.

EDIT: Użyłem FOR bo jest wygodniej. Nie robiłem sprawdzania nazwy bo po co? Wyniki są liczone dla kolejnych kolumn i stąd po kolei będzie to wyliczone dla: drewna, śrubek, kleju i farby. Stąd też właśnie pętla do 4 jedzie (IMG:style_emoticons/default/smile.gif) Ja użyłem wzoru na odchylenie:

odchylenie = pierwiastek ( ( suma_kwadratów_wszystkich_wartości / liczba_wartości ) - kwadrat_średniej )
Nie wiem czy tego akurat używasz, ale jest ten wzór równoważny z:
odchylenie = pierwiastek ( ( ( do_kwadratu(wartość - średnia) ) / liczba_wartości ) )

EDIT2: Doczytałem Twoje dodatkowe pytania... Podane rozwiązanie z minimalnymi modyfikacjami może służyć jak chciałeś. Na ten moment działa jeśli będziesz zwiększał liczbę rekordów dla kolejnych dni. Założyłem, że wszystkie rekordy są pełne, a więc zawierają dane. jeśli by tak nie było to musisz sobie poprawić zapytanie by sprawdzało i liczyło tylko dla tych wierszy gdzie w danej kolumnie SĄ jakieś wartości i liczyło ile ich jest.
Rozwiązanie jest skalowalne także o kolejne produkty, ale do SELECT w zapytaniach wtedy musisz dodawać dodatkowe kolumny wynikowe oraz przy samym obliczaniu zmienić w pętli FOR liczbę iteracji na taką, by pasowała do liczby produktów. Teraz są 4 ale może być ich więcej. Pamiętaj, że ja założyłem, iż wszystkie pola w tabeli są wypełnione. Jeśli tak nie jest to musisz sobie zapytania i kod dopasować do własnych potrzeb.

Ten post edytował thek 27.08.2009, 00:08:47
Go to the top of the page
+Quote Post
damianprz
post
Post #7





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


  1. Średnia wynosi: 10.625, a odchylenie: 3.903123748999
  2. Średnia wynosi: 15, a odchylenie: 5.5901699437495
  3. Średnia wynosi: 20, a odchylenie: 5.5901699437495
  4. Średnia wynosi: 18.125, a odchylenie: 9.3332403269175


Pomysł bardzo fajny
Dziękuje za pomoc

Po dodaniu nowych rekordów średnia będzie nadal liczona poprawnie.
Tylko, że jest problem taki, że gdy dodam do tabeli nowy produkt to raz że trzeba zmieniać dopisując
  1. sum(popyt_nowyprodukt) AS suma_no FROM popyt

i tu zmieniając 4 na 5
  1. for($i = 0; $i < 5; $i++)

Dodatkowo gdy nowy produkt zacznie mieć wpisywane wartości od id=9 to 8 pierwszych pozycji będzie pustych a skoro są na NOT NULL to będą brane chyba zera do średniej

Problem polega na tym, że marzy mi się kod który będzie stały, którego nie trzeba będzie zmieniać po każdym dodaniu produktu
Tylko że SELECTA chyba w pętle wziąźć nie można żeby zrobić coś w stylu
  1. $n=liczba kolumn zawierająca nazwę popyt_%
  2. % - zastępuje dowolny ciąg znaków
  3. SELECT popyt_% FROM popyt


Kolega z innego forum proponuje coś w tym stylu:

nowy projekt bazy danych:
(IMG:http://ambitni.eu/files/thumbs/t_1_313.png)
przykładowa tabela:
(IMG:http://ambitni.eu/files/beztytuu_799.png)

Proponuje taki kod:
  1. SELECT AVG(popyt),STD(popyt) FROM popyt WHERE towary_id=1;


Tylko że też jest problem bo policzy to dla Id=1 i jak damy to dla 2 3 i 4 ale jak zrobić żeby dodać 5 produkt i żeby nie dodawać linijki
  1. SELECT AVG(popyt),STD(popyt) FROM popyt WHERE towary_id=5;

Go to the top of the page
+Quote Post
thek
post
Post #8





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Problemy które poruszasz w poście zaznaczyłem po obliczeniach. Stąd właśnie pisałem by wtedy zmodyfikować to do potrzeb. Kompletnie jednak zapomniałem, że przecież MySQL ma własne funkcje statystyczne (IMG:style_emoticons/default/smile.gif) Wtedy liczenie niemal kompletnie Ci odpada. Jeśli masz wszystkie rekordy zapełnione to robisz tylko
  1. SELECT AVG(popyt_drewno), AVG(popyt_srubki), AVG(popyt_klej), AVG(popyt_farba) FROM tabela

  1. SELECT STD(popyt_drewno), STD(popyt_srubki), STD(popyt_klej), STD(popyt_farba) FROM tabela

A w pętli for tylko byś te dane wyświetlał i nic więcej.

Gdy mowa o wyeliminowaniu pustych, lepiej "obrócić zapytania" i wywoływać dla konkretnych kategorii popytu, wyrzucając z zapytania wszystkie będące NULLami
Trzymając się Twojego układu tabel dla kolumny drewno jest to:
  1. SELECT AVG(popyt_drewno) AS srednia, STD(popyt_drewno) AS odchylenie FROM tabela WHERE popyt_drewno IS NOT NULL

W przypadku jednak bardzo dużej elastyczności rozwiązania warto pomyśleć o przebudowie tabeli i pomysł zaproponowany na tamtejszym forum jest jak najbardziej poprawny.
Jeśli przyjmiemy więc, że baza wygląda jak z innego forum to możemy zrobić automatykę (IMG:style_emoticons/default/smile.gif)
  1. SELECT towary_id, avg(popyt) AS srednia, std(popyt) AS odchylenie FROM tabela GROUP BY towary_id

Grupujesz po towarach i dla tych zgrupowanych liczysz średnią oraz odchylenie.

Ja się dostosowywałem do Twojej bazy danych, ale jak widzisz odpowiednie zaprojektowanie tabeli potrafi przynieść lepsze efekty. Jako przyspieszacz ustawiłbym index na towary_id, a samo id można w zasadzie wyrzucić. Nazwy towarów możesz dorzucić jako osobną tabelę (z polami nazwa i id), które łączysz z towary_id by uzyskać nazwę towaru. Datę mimo wszystko bym zostawił wewnątrz dopóki jest mało produktów. Gdy będzie ich wiele dorzuciłbym pole wskazujące na datę z tabeli z datami (IMG:style_emoticons/default/smile.gif)

Czyli w maksymalnie rozwiniętej wersji mamy:
Tabela Data:
id(int), data(date)

Tabela Towar:
id(int), nazwa(varchar)

Tabela Produkty:
id_daty(int), id_towaru(int), popyt(double)

Teraz wyświetlanie wyników to:
  1. SELECT t.nazwa, p.towary_id, avg(p.popyt) AS srednia, std(p.popyt) AS odchylenie FROM Produkty p LEFT JOIN Towar t GROUP BY p.towary_id


Ten post edytował thek 27.08.2009, 13:17:06
Go to the top of the page
+Quote Post
damianprz
post
Post #9





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


(IMG:http://images39.fotosik.pl/184/e75ca425f3300656m.jpg)

Na screenie widać 3 tabelki które zrobiłem wg twojej instrukcji
W napisanych zapytaniach są błędy

  1. SELECT towary_id, avg(popyt) AS srednia, std(popyt) AS odchylenie FROM tabela GROUP BY towary_id

a ma być tak jak na screenie czyli
  1. SELECT id_towaru, avg(popyt) AS srednia, std(popyt) AS odchylenie FROM Produkty GROUP BY id_towaru


Jak widać na screenie zostały policzone wartości średnich i odchyleń
I są to poprawne wartości bo dane jaki zapisałem w tabeli (te 32 rekordy) są takie same jak w poprzedniej tabeli i wyniki są identyczne

Nie kapuje tego wyświetlania wyników
  1. SELECT t.nazwa, p.towary_id, avg(p.popyt) AS srednia, std(p.popyt) AS odchylenie FROM Produkty p LEFT JOIN Towar t GROUP BY p.towary_id

O co chodzi z tym t.nazwa Co to jest to t. czy p.

Gdy wpisałem ten kod w myPhPAdmin to zwraca mi błąd

  1. MySQL zwrócił komunikat:
  2. #1064 - Something is wrong in your syntax obok 'GROUP BY p.towary_id LIMIT 0, 30' w linii 1


Gdy poprawie na

  1. SELECT t.nazwa, p.id_towaru, avg(p.popyt) AS srednia, std(p.popyt) AS odchylenie FROM Produkty p LEFT JOIN Towar t GROUP BY p.id_towaru

to wyskakuje
  1. MySQL zwrócił komunikat:
  2. #1064 - Something is wrong in your syntax obok 'GROUP BY p.id_towaru LIMIT 0, 30' w linii 1


Jak wyświetlić te wyniki?
Go to the top of the page
+Quote Post
thek
post
Post #10





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Bo z rozpędu nie dopisałem warunku łączenia (IMG:style_emoticons/default/winksmiley.jpg)
  1. SELECT t.nazwa, p.id_towaru, avg(p.popyt) AS srednia, std(p.popyt) AS odchylenie FROM Produkty p LEFT JOIN Towar t ON p.id_towaru = t.id GROUP BY p.id_towaru

Przy złączeniach jeśli do wyniku przekazuję kolumnę z jakiejś tabeli to muszę wskazać jaką i z której. Używa się do tego składni nazwa_tabeli.nazwa_kolumny, ale jeśli sobie ustawię alias to mogę użyć aliasu... Stąd gdy zadeklarowałem Towar t, mogę się posługiwać t jak pseudonimem a składnia t.nazwa_kolumny jest równoważna Towar.nazwa_kolumny i to samo w przypadku Produktu (IMG:style_emoticons/default/winksmiley.jpg) Aliasy są często stosowane bo skracają zapytania mające długie nazwy tabel i w przypadku łączenia tabeli z samą sobą (a często się tak robi).
Równie dobre i być może szybsze będzie zapytanie
  1. SELECT * FROM (SELECT id_towaru, avg(popyt) AS srednia, STD(popyt) AS odchylenie FROM Produkty GROUP BY id_towaru) p LEFT JOIN Towar t ON p.id_towaru = t.id
To teraz najpierw zrobi wszystko i zwróci 4 rekordy, do których dopiszesz nazwy towarów. W pierwszym przypadku (w którym zapomniałem dopisać warunku łączenia) najpierw przypisało wszystkim rekordom nazwy produktów, a potem liczyło.

Ten post edytował thek 27.08.2009, 16:08:12
Go to the top of the page
+Quote Post
damianprz
post
Post #11





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Możesz mi sprawdzić czy to jest OK?
Do wyświetlania tego co się policzyło (IMG:style_emoticons/default/smile.gif)
Chyba działa bo otrzymałem taką tabelkę jako wynik:

nazwa id srednia odchylenie
drewno 1 10.625 3.903123748999
srubki 2 15 5.5901699437495
klej 3 20 5.5901699437495
farba 4 18.125 9.3332403269175


  1. $zapytanko2="SELECT t.nazwa, p.id_towaru, avg( p.popyt ) AS srednia, std( p.popyt ) AS odchylenie
  2. FROM Produkty p
  3. LEFT JOIN Towar t ON p.id_towaru = t.id
  4. GROUP BY p.id_towaru
  5. ";
  6. $rezultat2 = mysql_query($zapytanko2)
  7. or die("Błąd zapytania");
  8.  
  9. $wiersze = mysql_num_rows($rezultat2);
  10.  
  11. echo '<table>';
  12. echo '<tr><td>nazwa</td><td>id</td><td>srednia</td><td>odchylenie</td></tr>';
  13.  
  14. for ($i=0; $i <$wiersze; $i++)
  15. {
  16. $wiersz = mysql_fetch_array($rezultat2);
  17. echo '<tr>';
  18. echo '<td>'.$wiersz['nazwa'].'</td>';
  19. echo '<td>'.$wiersz['id_towaru'].'</td>';
  20. echo '<td>'.$wiersz['srednia'].'</td>';
  21. echo '<td>'.$wiersz['odchylenie'].'</td>';
  22. echo '</tr>';
  23. }
  24. echo '</table>';


Ten post edytował damianprz 27.08.2009, 16:22:02
Go to the top of the page
+Quote Post
thek
post
Post #12





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Kod wygląda poprawnie. W sumie chyba jedynie nie musisz wyświetlać informacji o id_towaru, bo to głównie informacja dla Ciebie i nie jest wymagana do wizualizacji (IMG:style_emoticons/default/winksmiley.jpg) Jeśli chcesz to możesz nawet ją usunąć z zapytania (usunięcie z SELECT kolumny: p.id_towaru) i pętli FOR.

PS: I chyba jako jeden z niewielu tutaj piszących nowych użytkowników zastosowałeś tabelki z sensem - do wyświetlania danych tabelarycznych, a nie układania layoutu strony "bo tak robią inni i tak pisze w książkach" (IMG:style_emoticons/default/winksmiley.jpg)

A jeśli byś bardzo chciał się standardów trzymać to zrobiłbyś jeszcze th i tbody (IMG:style_emoticons/default/tongue.gif) A by już super wszystko wyglądało to idealne dotrzymanie się standardów tabel z tfoot, thead itp oraz rozłączenie tagów HTML od kodu PHP... Ale to już dla purystów i zatwardziałych miłośników poprawności kodu od każdej możliwej strony (IMG:style_emoticons/default/winksmiley.jpg) Oby dalszy Twój forumowy byt i tematy tutaj były równie owocne. Przynajmniej robisz ze swojej strony co potrafisz i nie czekasz tylko na wyniki, tylko grzebiesz gdzie się da, pytasz, szukasz i słuchasz co się do Ciebie pisze. Nie każdemu tutaj się chcę (IMG:style_emoticons/default/smile.gif) Myślę, że na ten moment pozostaje tylko problem Ci już z wizualizacją wyników na stronie czy gdzie chcesz i ewentualne "panel administracyjny" do wprowadzania danych do bazy lub usuwania ich z niej czy też edycji (IMG:style_emoticons/default/smile.gif) Ale to już temat albo do samodzielnego opracowania, albo do podszkolenia swoich umiejętności, bo sedno tematu już zostało wyjaśnione i kodem poprawnym poparte. A obecny uważam jako minimalista za w pełni wystarczający. Teraz już tylko można go upiększać od strony wizualnej i ewentualnie starać pisać poprawny kod HTML, walidujący się i będący zgodny ze wszelkimi standardami (IMG:style_emoticons/default/smile.gif) Życzę w tym powodzenia (IMG:style_emoticons/default/smile.gif)

Ten post edytował thek 27.08.2009, 20:24:44
Go to the top of the page
+Quote Post
damianprz
post
Post #13





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Dzięki stary za pomoc
Powyższe obliczenia stosuje do pracy magisterskiej
Mam za zadanie zrobić w PHP prostą aplikację do zarządzania zapasami
Użytkownik aplikacji ma za zadanie wpisywać dane popytu poszczególnych towarów oraz ustalić pewne wartości typu
-oczekiwany poziom obsługi POP (np. 95%, czyli że brak zapasu może wystąpić 5 razy na 100 przypadków)
-czas uzupełnienia zapasu T np 2 dni
-czas przeglądu zapasu T0 np 6 dni
I co 6 dni roboczych czyli co tydzień (przykładowo) aplikacja będzie liczyła wielkość zamówienia poszczególnych towarów
Do obliczenia tego potrzebne będą te stałe wartości POP T T0 oraz właśnie wyliczone przez nas wspólnie (głównie przez Ciebie (IMG:style_emoticons/default/smile.gif) ) średnie popyty i odchylenia standardowe
Będzie trzeba zrobić kolejną tabelę w której znajdą się pewne wielkości dla każdego towaru takie jak obecny stan zapasu czy właśnie popyt średni i odchylenie które muszą być aktualizowane za każdym razem gdy je wyliczymy
Otrzymujemy wyniki:
nazwa id srednia odchylenie
drewno 1 10.625 3.903123748999
srubki 2 15 5.5901699437495
klej 3 20 5.5901699437495
farba 4 18.125 9.3332403269175
i te pogrubione dane musimy wprowadzić (zaktualizować) do tej innej tabeli
Hmm tylko jest znowu mały problem bo te dane mogą dotyczyć 4 towarów lub więcej
I teraz opcja "dodanie nowego towaru" powinna zwiększyć liczbę towarów w tabeli Towar (tam gdzie jest Id i Nazwa)
ale także powinna zwiększyć liczbę towarów w tabeli gdzie są przechowywane dane (obecny stan zapasu, popyt średni i odchylenie)
I jeśli policzymy średnie i odchylenia to muszą one zostać dodane do tej tabeli w każdej ilości, czy mamy 4 pary średnia-odchylenie czy więcej
Da się to zrobić?

Go to the top of the page
+Quote Post
thek
post
Post #14





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




No jasne. Zauważ, że grupujesz dane po id_towaru. Nieważne więc ile ich jest. Zawsze policzy te dane dla tylu, ile jest różnych id_towaru. Nieważne czy będzie to 3, 33 czy 3333 (IMG:style_emoticons/default/smile.gif) Oczywiście im więcej danych tym dłuższy czas obliczeń. Ale nie sądzę by nagromadziło się ich tyle by znacząco trzeba było czekać na wyniki (IMG:style_emoticons/default/winksmiley.jpg)

W tym momencie masz dorobić, jeśli dobrze zrozumiałem, tabelę przechowującą informację o danych statystycznych dla tego towaru. Czyli tabela o kolumnach:
id_towaru, średnia, odchylenie, stan

Jeśli tak, to wyliczone za każdym razem dane od razu można użyć jako UPDATE w tej nowej tabeli. Na pewno masz gdzieś dane dotyczące obecnego stanu danego produktu. Zapytanie więc pobierało by tę daną pomniejszoną o popyt z danego dnia, no chyba, że to już gdzieś automatycznie by odejmowało i stan byłby "na bieżąco".
Załóżmy, że jest tabela przechowująca stan każdego z produktów i mająca inne dane (jakaś o nazwie hmmm... Stan ? (IMG:style_emoticons/default/winksmiley.jpg) ) oraz możemy to połączyć z już obliczonymi wynikami średnimi i odchyleniami bo w końcu mamy łączącą je kolumnę id_towaru jako klucz.
  1. SELECT c.*, s.aktualny_stan FROM ( SELECT t.nazwa, p.id_towaru, avg( p.popyt ) AS srednia, std( p.popyt ) AS odchylenie FROM Produkty p LEFT JOIN Towar t ON p.id_towaru = t.id GROUP BY p.id_towaru) c LEFT JOIN Stan s ON c.id_towaru = s.id_towaru
Świetnie. Właśnie połączyliśmy wyniki ze stanem... Pozostaje jedynie zapisać je w tabeli nadzorującej co się dzieje. Niech to będzie Raport o polach jakie podałem na początku.
  1. UPDATE Raport r LEFT JOIN (tutaj walnij cale powyższe zapytanie) w ON r.id_towaru = w.id_towaru SET r.srednia = w.srednia, r.odchylenie = w.odchylenie, r.stan = w.aktualny_stan

Zauważ, że można część widoczna pod aliasem w optymalizować poprzez usuwanie z podzapytań kolumn jakie nie są nam potrzebne. A więc tak naprawdę możemy wyrzucić całkowicie łączenie z tabelą Towary (bo nie potrzebujemy w tym wypadku nazwy (IMG:style_emoticons/default/smile.gif) ) i skrócić zapytanie do:
  1. UPDATE Raport r LEFT JOIN ( SELECT p.*, s.aktualny_stan FROM ( SELECT id_towaru, avg( popyt ) AS srednia, STD( popyt ) AS odchylenie FROM Produkty GROUP BY id_towaru) p LEFT JOIN Stan s ON p.id_towaru = s.id_towaru ) w ON r.id_towaru = w.id_towaru SET r.srednia = w.srednia, r.odchylenie = w.odchylenie, r.stan = w.aktualny_stan
Przypatrz się temu zapytaniu, bo z reguły takie podejście do UPDATE wielu rekordów jednocześnie poprzez użycie LEFT JOIN by połączyć tabelę z danymi starymi i nowymi a potem nadpisanie odpowiednich kolumn wartościami innej kolumny jest czymś rzadko stosowanym, choć przydatnym, gdyż nie trzeba odwoływać się za każdym razem do jakiegoś identyfikatora w warunku WHERE, co jest najczęściej stosowana formą rozpoznawania jaki wiersz mamy uaktualniać (IMG:style_emoticons/default/smile.gif) Ja tak sobie parę dni temu zautomatyzowałem aktualizację jakichś 400-500 rekordów w bazie (IMG:style_emoticons/default/winksmiley.jpg)
Zakładam, że w nowej tabeli są już jakieś domyślne rekordy dla produktów o tym id, choćby puste. Jeśli nie to zrób INSERT i tyle (IMG:style_emoticons/default/smile.gif)
Powinniśmy po tym działaniu w tej tabeli mieć zawsze tyle rekordów ile jest produktów. Jeśli teraz będziesz chciał wyświetlić te dane to robisz:
  1. SELECT t.id, r.* FROM Raporty r LEFT JOIN Towary t ON r.id_towaru = t.id
Możesz jednak rozwiązać to nieco inaczej. Możesz dodać jeszcze dodatkową kolumnę z datą, dzięki temu zapytanie uruchomione po zakończeniu wprowadzania popytów z danego dnia stworzy rekordy w tej bazie zamiast je uaktualniać. Dzięki temu będziesz miał dane o średniej, odchyleniu i stanie dla każdego produktu z dowolnego dnia. Oczywiście jeśli już przechowujesz informację o stanie produktu na każdy dzień w innej tabeli, to nie ma sensu jej dublować także tu. Od tego posłuży ewentualny JOIN z tamtą tabelą i wyciagnięcie stanu na interesujący nas (IMG:style_emoticons/default/smile.gif) Na upartego to odpowiednio zaplanowawszy bazę można dzięki temu tworzyć raporty obejmujące określone okresy czasu. Osobiście jednak uważam, że od tego praca magisterska jest, aby samemu coś zrobić. Możesz nie wierzyć, ale ja swoją zrobiłem od A do Z samodzielnie, bo temat wybrałem sobie taki, że nie miałem szans na znalezienie gotowca w necie ("Analiza wydajnościowa technik animacji komputerowej przedstawicieli systemów operacyjnych rodziny Windows i Linux w środowisku Maya"). W przerwach zaś jednemu kolesiowi pisałem bardzo prosty CRM do jego magisterki. Nie płacił wiele to i wiele funkcji nie dostał (IMG:style_emoticons/default/winksmiley.jpg) Zresztą napisanie samemu pracy sprawi, że na obronie z Twojej pracy Cię nie zagną nawet najbardziej wrednymi pytaniami. Dla mnie najtrudniejszym było: "Jak Pan sobie wyobraża wykorzystanie tej pracy. Do czego może się ona przydać? Jak ja rozwinąć by można". A na to odpowiedź znałem od momentu gdy poznałem wyniki swoich pomiarów (IMG:style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
damianprz
post
Post #15





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Oj kolego thek, co ja bym bez Ciebie zrobił (IMG:style_emoticons/default/smile.gif)
Dzięki za pomoc. Poświęciłeś dużo czasu zeby mi pomóc.
Szacunek dla Ciebie, bo takich osób dużo nie ma.
Spróbuje zastosować twoje ostatnie podpowiedzi i jak zadziała to dam znać.
Go to the top of the page
+Quote Post
thek
post
Post #16





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




A ja życzę powodzenia w kodzie php/html i analizie oraz tworzeniu własnych zapytań (IMG:style_emoticons/default/smile.gif) A później także z obroną (IMG:style_emoticons/default/smile.gif) Wrzesień już niemal, a jak sądzę w połowie września będzie obrona, czyli za pasem (IMG:style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post
damianprz
post
Post #17





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Ponoć ma być raczej pod koniec września tak żeby jeszcze do połowy września był czas na analizy z promotorem
Trzeba się sprężyć

Przeczytałem twoje ostatnie podpowiedzi i sie zastanawiam na d ilością tabel
bo proponujesz tabele

Stan (Załóżmy, że jest tabela przechowująca stan każdego z produktów i mająca inne dane (jakaś o nazwie hmmm... Stan ?)
i
Raport (id_towaru, średnia, odchylenie, stan)

I tu jest stan i tu jest stan i troszkę nie bardzo rozumiem po co
Moja tabela w której są obecne wyniki zapasów (stan zapasu, srednia, odchylenie) wygląda tak

zapasy
id_towaru ......... int(10) .......... Nie 0
Nazwa ..........varchar(30) ....... Nie
stan .............int(10) ........... ..Nie 0
srednia .......... int(10) ......... .Nie 0
odchylenie ........... int(10) ...... Nie 0

i pasuje te wyniki które policzyliśmy dla każdego towaru (średnia odchylenie)
tutaj zapakować

gdzieś bedzie opcja żeby wyskoczyło okno do wpisania popytów z danego dnia i pracownik codziennie bedzie wpisywał te popyty a kod bedzie uaktualniał tabele Podukty
Co jakiś okres czasu (zależnie od ustawienia T0 - czas przeglądu zapasu, np 6 dni czyli co tydzień) bedzie wyskakiwał monit żeby zamówić dostawy towarów
i wtedy pracownik kliknie na Oblicz średnią i odchylenie, te dane sie zaktualizują, obecny stan zapasu bedzie zaktualizowany na bieżąco (codziennie) i jakiś kod wygeneruje ile każdego zapasu trzeba zamówić. I to mniej wiecej tyle

Tworzenie tabeli Stan i tabeli Raport nie jest konieczne prawda? Można po prostu dane wpakować do 1 tabeli co nie? do tej mojej Zapasy
Jeśli chodzi o daty to za bardzo nie chce sie z nimi bawić. Z resztą sam widzisz, że mistrzem php czy mysql to nie jestem (IMG:style_emoticons/default/sad.gif)
Chyba tylko data bedzie przy wstawianiu dziennego popytu i daty beda wyświetlane gdy ktos bedzie chciał zobaczyć tabele z dziennym popytem

EDIT:
  1. UPDATE zapasy LEFT JOIN
  2. ( SELECT id_towaru, avg(popyt) AS srednia, STD(popyt) AS odchylenie FROM produkty GROUP BY id_towaru)
  3. ON zapasy.id_towaru = produkty.id_towaru
  4. SET zapasy.srednia = produkty.srednia, zapasy.odchylenie = produkty.odchylenie

Coś nie chce chodzić. Wywala błąd:
  1. MySQL zwrócił komunikat:
  2.  
  3. #1064 - Something is wrong in your syntax obok
  4. 'LEFT JOIN ( SELECT id_towaru, avg(popyt) AS srednia, STD(popyt)'
  5. w linii 1


.

11

Ten post edytował damianprz 28.08.2009, 13:39:34
Go to the top of the page
+Quote Post
thek
post
Post #18





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Zapytanie sypie Ci błąd bo nie nadałeś aliasu dla podzapytania... Zauważ, że po nawiasach nie masz nazwy tego, choć sądząc z całości powinno tam być napisane produkty. Tworzenie tabeli nie jest konieczne. Ważne byś miał gdzieś możliwość przechowania informacji o aktualnych danych jakie wyliczasz i tych jakie potrzebujesz (jak aktualny stan produktu). Może to być wspomniana Zapasy czy jakakolwiek inna, która jest związana bezpośrednio z danym produktem (drewnem, śrubkami) poprzez id_towaru. Opisana przez Ciebie dobrze pasuje, z jednym małym zastrzeżeniem. Średnia i odchylenie muszą być wartościami zmiennoprzecinkowymi, czyli FLOAT lub DOUBLE, bo inaczej przytnie Ci wartości za przecinkiem, gdyż pole to masz na int ustawione. Wygodniej będzie double bo ma większą precyzję.

Ten post edytował thek 28.08.2009, 21:38:38
Go to the top of the page
+Quote Post
damianprz
post
Post #19





Grupa: Zarejestrowani
Postów: 41
Pomógł: 0
Dołączył: 26.08.2009
Skąd: Zamojsce

Ostrzeżenie: (0%)
-----


Już wcześniej ustawiłem wartości na double z obawy że UPDATE mógł wywalać jakiś błąd próbując wprowadzić do rekordu INT wartość niecałkowitą

Ten UPDATE nadal nie działa

Ten post edytował damianprz 28.08.2009, 22:14:14
Go to the top of the page
+Quote Post
thek
post
Post #20





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Nie dublujmy może tematów i skupmy się w jednym (IMG:style_emoticons/default/winksmiley.jpg) UPDATE na 100% działa, ale to jest UPDATE a nie INSERT, więc w bazie Zapasy muszą już istnieć rekordy z id_towaru równym produktom jakie w zapytaniu obrabiasz. Zapytanie działa i jest ono w osobnym temacie, który dlań założyłeś. Ale by nie skakać to tu masz je powtórzone:
  1. UPDATE zapasy z LEFT JOIN (SELECT id_towaru, avg( popyt ) AS srednia, STD( popyt ) AS odchylenie FROM produkty GROUP BY id_towaru) p ON z.id_towaru = p.id_towaru SET z.srednia = p.srednia, z.odchylenie = p.odchylenie
Innych kolumn i tabel nie ruszam bo to zbędne. I jeszcze raz zaznaczam. UPDATE mozna zrobić tylko na tych rekordach, które istnieją. A będą one istniały w wersji finalnej, gdyż powstaną zapewne jako puste i wyzerowane w momencie dodania nowego produktu do bazy. No ale to już Twoja działka jako tworzącego stronę, by o tym pamiętać (IMG:style_emoticons/default/winksmiley.jpg)
Go to the top of the page
+Quote Post

2 Stron V   1 2 >
Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 15.12.2025 - 19:50