Avatar billede Slettet bruger
31. maj 2002 - 14:39 Der er 24 kommentarer og
1 løsning

Tricky SELECT

Hejsa... jeg har et KÆMPE effektivitetsproblem:

$firstresult = mysql_query("SELECT * FROM stat_hits WHERE path = '$path'");

while($row = mysql_fetch_array($firstresult)){
$secondres = mysql_query("SELECT * FROM stat_hits WHERE sesid = '".$row["sesid"]."' AND date > '".$row["date"]."' ORDER BY date ASC LIMIT 1");

while($row2 = mysql_fetch_array($secondres)){

if(3600 > (strtotime($row2["date"])-strtotime($row["date"])) and (strtotime($row2["date"])-strtotime($row["date"])) > 5){

$points = (strtotime($row2["date"])-strtotime($row["date"])) + $points;
$devideby++;

}
}
}

Tabelen ser sådan her ud: [SESID|DATE|PATH] og med den kan man tracke brugere, sesid er php's sessionid og resten gir sig selv. Path der den aktuelle side... Med følgende stump kode kan jeg få gennemsnitstiden en bruger er om at besøge på hjemmesiden med

echo round($points/$devideby)." sekunder";

men findes der ikke en mere optimeret løsning da det tager ca 6 sek hvis der har været 200 visninger af en side...

Jeg kunne forestille mig at det kunne lade sig gøre hvis jeg havde en eksakt kopi af tabellen, og derefter lavede et "dobbelttabelsselect" men findes der en måde så jeg kan fx lave et alias til tabellen... for så var livet sq meget lettere...
Avatar billede hansk Nybegynder
31. maj 2002 - 14:47 #1
Du kan joine tabellen sammen med sig selv på denne måde:

SELECT * FROM stat_hits A, stat_hits B
WHERE A.path = '$path'
AND B.sesid = A.sesid AND B.date > A.date
ORDER BY B.date ASC LIMIT 1
Avatar billede Slettet bruger
31. maj 2002 - 14:55 #2
Kewl!! Jeg havde set noget med Join men jeg havde aldrig lige fattet hvad det gik ud på ... det var sq smart... jeg tester lige... pointene kommer snart...
Avatar billede Slettet bruger
31. maj 2002 - 14:59 #3
Hvis du lige kan smide gennemsnit ind, så kunne det være super... men der lidt problemer i sær med LIMIT 1, selv om jeg jo kun skal have den tid der ligger LIGE efter den oprindelige...
Avatar billede Slettet bruger
31. maj 2002 - 15:06 #4
Ah... jeg har en ide... finde minimumsværdien mellem de to dates og selecte den der har den...
Avatar billede hansk Nybegynder
31. maj 2002 - 15:12 #5
Uden at jeg lige kan gennemskue din beregning skal det måske gøres sådan her:

WHERE (strtotime(B.date)-strtotime(A.date)) between 5 and 3600.

Jeg er ikke så stærk til php eller hvilket sprog det nu er lavet i.
Hvis du siger hvad du vil have ud af sql'en, skal jeg se hvad der kan laves.
Avatar billede Slettet bruger
31. maj 2002 - 15:19 #6
Jeg har følgende select og det er det jeg skal bruge har jeg fundet ud af:

SELECT *,MIN(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) AS mindif, AVG(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) AS gennemsnittet FROM stat_hits A, stat_hits B WHERE A.path = '/Nyheder' AND B.sesid = A.sesid AND B.date > A.date AND mindif = (UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date))
Avatar billede Slettet bruger
31. maj 2002 - 15:19 #7
men jeg får flg fejl


Unknown column 'mindif' in 'where clause'
Avatar billede hansk Nybegynder
31. maj 2002 - 15:24 #8
Du må ikke bruge kolonnen mindif i din WHERE clause. Du bliver nødt til at bruge hele beregningen.
Avatar billede hansk Nybegynder
31. maj 2002 - 15:26 #9
mindif er ikke en kolonne, og er derfor ikke tilladt i WHERE.
Avatar billede Slettet bruger
31. maj 2002 - 15:26 #10
Det kan den ikke... desværre... den laver en anden fejl
SQL-forespørgsel : 

SELECT *, AVG(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) AS gennemsnittet FROM stat_hits A, stat_hits B WHERE A.path = '/Nyheder' AND B.sesid = A.sesid AND B.date > A.date AND MIN(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) = (UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) LIMIT 0, 30

MySQL returnerede:


Invalid use of group function
Avatar billede hansk Nybegynder
31. maj 2002 - 15:35 #11
Ja, selvfølgelig. MIN, MAX, AVG er jo gruppefunktioner og de kan naturligvis ikke benyttes i WHERE clauses.
MySQL supporterer desværre heller ikke sub-selects, så der kan den heller ikke fixes.
Prøv i stedet at sortere på kolonnen, så vil du kunne bruge LIMIT til at få de rigtige rækker ud.
Avatar billede Slettet bruger
31. maj 2002 - 15:42 #12
Det sq ærgeligt... hvad hvis jeg bruger noget lign GROUP BY sesid
Avatar billede Slettet bruger
31. maj 2002 - 15:45 #13
Hvis jeg bruger subselects... så er jeg jo ligevidt
Avatar billede hansk Nybegynder
31. maj 2002 - 15:58 #14
En sub select i SQL verdenen er en select som ser sådan ud:

select ..... where field in (select field from table)

Den ville speede din funktion betydeligt op, da du ville slippe for de meste af kommunikationen mellem dine oprindelige selects.
Avatar billede hansk Nybegynder
31. maj 2002 - 16:03 #15
Jeg bliver desværre nødt til at løbe nu,´men jeg skal gerne kigge på det i løbet af weeekenden.
Avatar billede Slettet bruger
31. maj 2002 - 16:08 #16
ok tak.. her er lidt point til at hjælpe på det...

Indtil videre virker:

SELECT AVG(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) AS gennemsnittet FROM stat_hits A, stat_hits B WHERE A.path = '/Nyheder' AND B.sesid = A.sesid AND B.date > A.date

Men jeg manger "bare" den sidste condition:

MIN(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) = (UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date))

Jeg har set der er noget der virker som WHERE som hedder HAVING.. Måske kan den hjælpe mig... det vil jeg da håbe...
Avatar billede hansk Nybegynder
01. juni 2002 - 16:12 #17
ok, denne fungerer:

SELECT
A.Path, A.SESID, A.Date, B.date,
AVG(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) AS gennemsnit
FROM
stat_hits A, stat_hits B
WHERE
A.path = '/Nyheder' AND B.sesid = A.sesid AND B.date > A.date
GROUP BY
A.Path, A.SESID, A.Date, B.date
HAVING
MIN(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date)) =
(UNIX_TIMESTAMP(B.date)-UNIX_TIMESTAMP(A.date))

Jeg forstår bare ikke helt hvad du forsøger.
Du har dataene [SESID|DATE|PATH], hvornår bliver de sat ind i databasen, er det når en bruger får vist en side? Så er dato vel det tidspunkt hvor siden bliver vist.
Men hvad viser så udtrykket a.date-b.date?
Avatar billede Slettet bruger
01. juni 2002 - 23:09 #18
ja.... a.date-b.date viser så hvor lang tid en bruger er om at klikke videre til den næste side.. så er AVG as gennemsnit den gennemsnitlige tid en bruger besøger en side, før han /hun går videre..
Avatar billede Slettet bruger
01. juni 2002 - 23:09 #19
jeg tester senere, men pga jeg ikke har fået mails hele dagen, er der lange svartider :D
Avatar billede Slettet bruger
01. juni 2002 - 23:13 #20
deprimerende den gør ikke som den burde!
Avatar billede hansk Nybegynder
01. juni 2002 - 23:15 #21
OK, så du måler den tid en bruger er inde på en side. Men hvis en bruger går over på en anden "site" får du vel ikke den information?
Avatar billede Slettet bruger
01. juni 2002 - 23:25 #22
nej! derfor B.date > A.date, for der skal jo eksistere en handling når han/hun går videre.... jeg synes bare det var en sjov feature! men den er lige processkrævende om det er php eller mysql der gør de... men tak for hjælpen!
Avatar billede tipsen Nybegynder
03. juni 2002 - 23:21 #23
Har du evt. overvejet at indeksere felterne i tabellen - det kan også give dig et boost!
Avatar billede Slettet bruger
03. juni 2002 - 23:32 #24
indexere? forklar!
Avatar billede Slettet bruger
03. juni 2002 - 23:38 #25
WOHAHOWWHAOHW!!!!!!!!! Det hjalp
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester