Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Serie danych
Forum PHP.pl > Forum > Bazy danych > MySQL
yarot
Witam,
mam taki problem.

Tabela
idtab iduser stan
1 100 1
2 200 1
3 100 1
4 100 1
5 200 1
6 200 0
7 100 1


Ok. chodzi o to aby pokazać zapytaniem serie danych.
Tzn w wyniku chciałbym mieć
Id User count
100 4
200 2

Widziałem gdzieś odpowiedź na podobne pytanie wygląda ono mniej więcej tak:

  1. SELECT d.idUser, MAX(d.SeriesLength) AS SeriesLength
  2. FROM (SELECT a.idUser, a.idTab, COUNT(*) AS SeriesLength
  3. FROM MyTable AS a
  4. INNER JOIN MyTable AS b ON b.idUser = a.idUser AND b.State = 'T' AND b.idTab >= a.idTab AND NOT EXISTS
  5. (SELECT *
  6. FROM MyTable AS c
  7. WHERE c.idUser = a.idUser AND c.idTab > a.idTab AND c.idTab < b.idTab AND c.State = 'F')
  8. WHERE a.State = 'T'
  9. GROUP BY a.idUser, a.idTab) AS d
  10. GROUP BY a.idUser


Ale w mysql się wykrzacza na podzapytaniu.
Jak to ugryźć ?
mhs
mysql nie obsluguje podzapytan... beda dopiero w przyszlosci...
yarot
Cytat(mhs @ 2004-10-25 13:50:39)
mysql nie obsluguje podzapytan... beda dopiero w przyszlosci...

Wiem i dlatego pytam czy da się to jakoś inaczej napisać ?
harmag
czy chodzi ci o to?

Kod
select iduser, count(*) from tabela where stan = 1 group by iduser;
Aztech
To powinno wystarczyć (chociaż to co napisał harmag też jest chyba ok smile.gif)
  1. SELECT iduser, count(stan) FROM tabela GROUP BY iduser;

a potem wyniki przez while i mysql_fetch_array smile.gif

a tak przy okazji tu jest bardzo podobny post TUTAJ
harmag
Cytat(Aztech @ 2004-10-25 18:59:32)
To powinno wystarczyć (chociaż to co napisał harmag też jest chyba ok smile.gif)
  1. SELECT iduser, count(stan) FROM tabela GROUP BY iduser;

a potem wyniki przez while i mysql_fetch_array smile.gif

a tak przy okazji tu jest bardzo podobny post TUTAJ

zwroc tylko uwage ze zliczac ma tylko uzytkownikow dla ktorych stan = 1 o ile sie nie myle smile.gif
Aztech
Masz racje.
Powinno być SUM(stan) zamiast Count(stan)
smile.gif
yarot
Cytat(Aztech @ 2004-10-25 20:59:32)
To powinno wystarczyć (chociaż to co napisał harmag też jest chyba ok smile.gif)
  1. SELECT iduser, count(stan) FROM tabela GROUP BY iduser;

a potem wyniki przez while i mysql_fetch_array smile.gif

a tak przy okazji tu jest bardzo podobny post TUTAJ

Panowie takie rzeczy się pisze spod dużego palca. smile.gif
Sprawa jest troche bardziej skomplikowana.
Nie napisałem może wyraźnie ale chodzi o najdłuższą serie danych.

Jeżeli przeanalizujecie przykład który zamieściłem na górze to zobaczycie że koncepcja jest dobra tylko nie działa w mysql ze względu na brak obsługi podzapytań.

Wasze przykłady zliczają liczbę wystąpień albo sumują a to nie to samo.
FiDO
Cytat
Nie napisałem może wyraźnie ale chodzi o najdłuższą serie danych.

Co przez to rozumiesz? Przyznaje sie bez bicia, ze nie do konca wiem do czego zmierzasz... Jedyne co mi przychodzi do głowy to to, ze chcesz wyciagnac pole iduser, ktore wystepuje w bazie najwiecej razy (liczymy tylko te ze stan = 1), ale mowisz, ze to cos skomplikowanego, a to raczej proste, wiec pewnie nie o to chodzi, ale na wszelki wypadek podam smile.gif
  1. SELECT iduser, SUM(IF(stan = 1, 1, 0)) ile FROM tabela GROUP BY iduser ORDER BY ile DESC LIMIT 1


Cytat
Jeżeli przeanalizujecie przykład który zamieściłem na górze to zobaczycie że koncepcja  jest dobra tylko nie działa w mysql ze względu na brak obsługi podzapytań.

Łatwo powiedziec, ale to juz nie jest prosty select, ktorego analiza zajmuje chwile, tymbardziej, ze nie wiedzac co chcesz osiagnac analiza jest jeszcze trudniejsza, wiec moze napisz po ludzku dla troche wiekszego zbioru danych (jak widzisz przy tym interpretacje nie sa jednoznaczne), co chcesz osiagnac.
yarot
Ok ja też się przyznaje bez bicia że uprościłem za bardzo ten przykład smile.gif

ok mamy w bazie rekordy powiedzmy:
Kod
idrekordu user stan
1         100    1
2         200    2
3         100    1
4         100    1
5         100    0
6         200    0
7         100    2
8         200    0
9         100    1
10        100   2
11        100    0
12        200    1
13        200    1
14        100    2
15        100     1
16         200    2
17         100    1
18          100   0
19         100    1
20         200    0

I teraz wyciągam z bazy i chce wiedzieć jaka była najdłuższa seria dla usera i stan = 1:
Kod
user   counterek
100    3
200    2


Nie wiem czy teraz jasno napisałem ale starałem się bardzo smile.gif
Tak czy siak dzięki że walczycie.
Aztech
Sluchaj to popatrz na twoj pierwszy post i powiedz jak sie ma to do tego co teraz piszesz!!!

Inna sprawa, po co podawać stan jak i tak zliczasz ile razy wystapil user, tzn to myli ludzi?

Na razie nie widze pomysłu jak to zrobić i czasu mam mało... pomyśle po tym jak jutro napisze kolokwium.

Narta
yarot
Cytat(Aztech @ 2004-10-26 18:44:06)
Sluchaj to popatrz na twoj pierwszy post i powiedz jak sie ma to do tego co teraz piszesz!!!

Inna sprawa, po co podawać stan jak i tak zliczasz ile razy wystapil user, tzn to myli ludzi?

Na razie nie widze pomysłu jak to zrobić i czasu mam mało... pomyśle po tym jak jutro napisze kolokwium.

Narta

Sorry ale mamy problem ze zrozumieniem się chyba. Ma się dokładnie tak samo tylko dałem za małą próbę rekordów.

Podaje stan bo mam taką potrzebę że chcę pokazać jaka była najdłuższa seria danych przy pewnym założeniu.

W definicji słowa najdłuższa seria danych chodzi o pokazanie ile razy z rzędu wynik pasuje do założonego warunku smile.gif
Niespełnienie warunku (wystąpienie warunku innego niż w założeniu) powoduje że liczymy serie danych od początku.

Zadałem to pytanie po angielsku na grupie sqlowej i wszyscy zrozumieli i podali odpowiedź ale w sql. Po polsku jest trudniej rzeczywiście bo to nasz język ojczysty tylko winksmiley.jpg.

Inna sprawa że gdybym chciał otrzymać to co napisałeś wcześniej to użyłbym opcji szukaj na forum i znalazł dziesiątki przykładów. Napisałem też aby uprościć temat, że koncepcja jest tylko nie potrafię tego przerobić na mysql-a bo nie obsługuje podzapytań.

Pozdrawiam.
Aztech
Zrozumieąłem dopiero za drugm przykładem - że chodzi o to ile razy wystapil user pod rząd - co nie zmienia faktu, że pierwsze pytanie było, źle przedstawione.
Piszesz
Cytat
I teraz wyciągam z bazy i chce wiedzieć jaka była najdłuższa seria dla usera i stan = 1:

a podajesz wynik
Cytat
user  counterek
100    3
200    2


To tyle i na ten temat sie nie wypowiadajmy.
Jak to zrobić to sie zastanowie.. na razie nie mam ponyslu
yarot
Cytat(Aztech @ 2004-10-27 10:06:25)
Zrozumieąłem dopiero za drugm przykładem - że chodzi o to ile razy wystapil user pod rząd - co nie zmienia faktu, że pierwsze pytanie było, źle przedstawione. To tyle i na ten temat sie nie wypowiadajmy. A nad pytaniem sie zastanowie

No własnie problem cały polega na tym że zależy mi na największej liczbie wystąpień usera i określonego stanu pod rząd a nie wystąpienia usera.




Next post:

Aztech właśnie podałem to co chce uzyskać.
Dokładnie chce wiedzieć jaka była najdłuższa seria wystąpień pod rząd (czyli seria) stanu równego 1 dla danego usera

i wyniki które płynnym ruchem dla przedstawionego przykładu podałem są poprawne.
user 100 3 sztuki (1,3,4)
user 200 2 sztuki (2,5)

była w tym przykładzie jeszcze seria
user 100 1 sztuka (na końcu 7)
ale jej nie pokazuje bo chce wiedzieć jaka była najdłuższa.

Teraz hyba jest jasne ?
SongoQ
Za pomoca samego SQL'a dla MySQLa jest to raczej nie wykonalne, jesli by ktos to rozwiazal na samym SQL'u dla tej bazki bardzo bym chcial zobaczyc zapytanie.

Odnosnie tego zapytania co podales w pytaniu, sprawdzales czy dobrze zwraca wyniki, bo analizujac to bez sprawdzania na bazie wydaje mi sie ze tam brakuje jednego zlaczenia tabelek.

  1. SELECT d.idUser, MAX(d.SeriesLength) AS SeriesLength
  2. FROM (SELECT a.idUser, a.idTab, COUNT(*) AS SeriesLength
  3. FROM MyTable AS a
  4. INNER JOIN MyTable AS b ON b.idUser = a.idUser AND b.State = 'T' AND b.idTab >= a.idTab AND NOT EXISTS
  5. (SELECT *
  6. FROM MyTable AS a
  7. INNER JOIN MyTable AS c
  8. WHERE c.idUser = a.idUser AND c.idTab > a.idTab AND c.idTab < b.idTab AND c.State = 'F')
  9. WHERE a.State = 'T'
  10. GROUP BY a.idUser, a.idTab) AS d
  11. GROUP BY a.idUser


Jesli ktos by mial za duzo czasu to prosze to sprawdzic.
yarot
Cytat(SongoQ @ 2004-10-27 12:58:08)
Odnosnie tego zapytania co podales w pytaniu, sprawdzales czy dobrze zwraca wyniki, bo analizujac to bez sprawdzania na bazie wydaje mi sie ze tam brakuje jednego zlaczenia tabelek.

Witaj, nie sprawdzałem bo nie miałem na czym za bardzo sad.gif

Gość na grupie napisał koncepcje którą w miare rozumiem tylko nie wiem jak zrealizować w mysql sad.gif
Aztech
a ile może być możliwych stanów? więcej niż tam podałeś?
spróbowałbym to zrobić za pomocą 2 zapytań - pierwsze wyciągałoby iduser oraz stan dany konkretny a wyszukanie w tym serii to juz chyba nie bylby klopot, ale przy duzej liczbie userow i stanow to troszeczke czasochlonne (ps. pisze to z zajec i nie moge teaz tej koncepcji sprawdzic - moze wieczorkiem)
SongoQ
A koniecznie musi byc to baza MySQL?

Do Aztech: Stan jest nie wazny, najwiekszy problem jest w zlaczeniu tabel i zsumowaniu kolejnych rekordow z danego kryterium i z tego zbioru co w MySQLu sie nie da zrobienie counta, pogrupowanie a nastepnie wyciagniecie maxymalniej wartosci.

No chyba ze masz jakis inny pomysl, chetnie zobacze rozwiazanie.
yarot
Cytat(Aztech @ 2004-10-27 13:26:46)
a ile może być możliwych stanów? więcej niż tam podałeś?
spróbowałbym to zrobić za pomocą 2 zapytań - pierwsze wyciągałoby iduser oraz stan dany konkretny a wyszukanie w tym serii to juz chyba nie bylby klopot, ale przy duzej liczbie userow i stanow to troszeczke czasochlonne (ps. pisze to z zajec i nie moge teaz tej koncepcji sprawdzic - moze wieczorkiem)

Liczba stanów jest rzeczywiście nie ważna wg mnie też.
Dokładnie jest ich 6
A seria interesuje mnie konkretnie dla (stan = 1 or stan = 5) ale jak ktoś zrobi przy 1 to sobie poradzę smile.gif

Można zrobić tempa ? Tylko własnie problemem jest chyba znalezienie serii mysqelem.
Wg mnie jeżeli ktoś ma algorytm na znalezienie serii to trzeba by było z tego zrobić tempa i potem wyciągnąć maksa - ale jak nie wiem sad.gif

Aha Aztech - zapytanie te może Ci się przydać do Twojego scrabla - chodzi konkretnie o liczbę kolejnych meczów bez porażki np. albo największą serię trafnych typów w typowaniu.

Problem można rozwiązać php ale ładowanie całej bazy kilku tysięcy rekordów jest chyba lekką paranoją sad.gif
FiDO
Wiem jak to zrobic w mysql z pomoca dwoch tabel tymczasowych i okolo 3-4 zapytan SELECT, jesli takie cos by Cie zadowolilo to napisz, a podrzuce rozwiazanie.
SongoQ
FiDO mozesz podeslac rozwiazanie na forum.

Chcialbym zobaczyc w jaki sposob podszedles do tego problemu.
yarot
Cytat(FiDO @ 2004-10-27 20:15:05)
Wiem jak to zrobic w mysql z pomoca dwoch tabel tymczasowych i okolo 3-4 zapytan SELECT, jesli takie cos by Cie zadowolilo to napisz, a podrzuce rozwiazanie.

Bardzo chętnie - wczoraj spędziłem parę godzin na walce z tabelami tymczasowymi ale poległem sad.gif
FiDO
Jednak jest maly problem, bo wczoraj nie wiedzialem, ze na tabelach tymczasowych nie mozna robic self-joinow... poki co poprostu wywalilem slowko TEMPORARY i na koncu mam DROP'owanie tej tabeli.

Wiec tak to leci po kolei:
Kod
CREATE TEMPORARY TABLE temp_serie (
 id INT,
 iduser INT,
 stan INT
);

CREATE TABLE temp_serie2 (
 iduser INT,
 stan INT,
 nr_serii INT,
 user_stan VARCHAR(10),
 ile INT
);

INSERT INTO temp_serie
 SELECT *
 FROM serie
 ORDER BY iduser,id;

SELECT @count := 0, @old := 'x';

INSERT INTO temp_serie2
 SELECT
   iduser, stan,
   @count := @count + IF(@old = 'x' OR @old <> CONCAT(iduser, '_', stan), 1, 0) nr_serii,
   @old := CONCAT(iduser, '_',stan) old,
   COUNT(*) ile
 FROM
    temp_serie
  GROUP BY
    nr_serii, old;

SELECT
 a.iduser,
 a.ile
FROM
  temp_serie2 a
LEFT JOIN
  temp_serie2 b ON (a.user_stan = b.user_stan AND a.ile < b.ile)
WHERE
  b.user_stan IS NULL AND a.stan = 1;

DROP TABLE temp_serie2;

([ code] zamiast [ sql] celowe, zeby zachowac formatowanie)

Oczywiscie wypadalo by jeszcze miedzy tymi zapytaniami dac LOCK TABLE, zeby zachowac spojnosc danych miedzy tymi tabelami. Dodatkowo jesli wywolywanie tego zestawienia wystepuje czesto, trzeba by troche inaczej rozegrac sprawe z ta druga tabela, ktora tymczasowa nie jest, zeby nie zdarzyla sie sytuacja w ktorej nastapi proba utworzenia tej tabeli a ona juz istnieje..
Wydaje mi sie tez, ze mozna to cala ta sprawe rozwiazac prosciej, ale jakos nie moge sie dostatecznie skupic, zeby wymyslec cos lepszego.
SongoQ
Wiedze ze pomysl jest ok. Jak by bylo takie cos jak podzapytanie to nie jest taki problem.

Jak w nocy bede mial chwile czasu to sporobuje powalczyc z tym tematem, bo naprawde problem jest "ciekawy".
FiDO
Cytat(SongoQ @ 2004-10-28 17:36:58)
Jak w nocy bede mial chwile czasu to sporobuje powalczyc z tym tematem, bo naprawde problem jest "ciekawy".

To fakt, ciekawe pytanie.. chetnie poznam optymalniejsze rozwiazanie tego bez uzycia subqueries.

PS. wlasnie sie zorientowalem, ze zostala wydana stabilna wersja MySQL z serii 4.1.x w ktorym podzapytania juz sa... czas najwyzszy. Teraz tylko czekac az sie zadomowia na wiekszosci serwerow.
SongoQ
Na pewno wydajnosc nie bedzie taka jak PGSQL'a czy ORACL'a, ale juz daja wieksze mozliwosci.
yarot
Witam,
w poszukiwaniu rozwiązania problemu serii znalazłem fajny sposób na obliczanie ciągów.
Oczywście w całości nie rozwiązuje problemu ale może się komuś przyda do innych celów.


http://www.mvps.org/access/queries/qry0018.htm

Pozdrawiam
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.