WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   klurig mySQL fråga (php) (https://www.wn.se/forum/showthread.php?t=1039423)

youheardit 2009-12-03 15:43

klurig mySQL fråga (php)
 
Hejsan!
Har nu stött på ett problem... jag driver sidan nyhetsarkiv.se och i systemet finns det tillgänglighet att kommentera en artikel.
Artiklarna ligger i en tabell och kommentarerna i en.
Men nu vill jag göra en lista över mest kommenterade artiklarna i form av "Mest diskuterade"... jag har googlat i säkert någon timme utan resultat.
kommentarerna har en kolumn "postid" som är id't på artikeln som kommentaren tillhör.

Någon som har en lösning? jag har försökt med array_sort() mm...
men får inte riktigt till det så den räknar av antal kommentarer per artikel...

Tacksam för svar!
Med vänliga hälsningar!
//Philip Andersson!

Magnus_A 2009-12-03 15:47

Något sånt här borde fungera:
select count(postid) as antal_kommentarer,
postid
from kommentartabellen
group by postid

youheardit 2009-12-03 16:29

$sql = "select count(pid) as antalet,
pid
from comments
group by pid";
while($line = mysql_fetch_assoc(mysql_query($sql))){
echo $line['pid'];
echo "<br>";
}
?>[/CODE]
pid = postid som i förra posten...

Resultatet blir en oändligt lång lista med samma pid som i första kommentaren...
Kod:

40
40
40
40
40
osv....

har jag gjort fel ? eller är mysql-frågan fel ställd?

tack! :)

youheardit 2009-12-03 16:36

jag skulle kunna tänka mig att det borde funka med att först använda någon form av array sort by count eller något och sedan köra array_unique på dem så får man ju fram listan...

danjel 2009-12-03 17:07

Du borde kunna köra något liknande:

select
pid,
(select count(*) from comments where pid=c.pid) as antalet
from comments c
order by antalet desc

Det kan vara snabbare än group by förutsatt att du har bra indexering..

youheardit 2009-12-03 17:22

Citat:

Ursprungligen postat av danjel (Inlägg 20333919)
Du borde kunna köra något liknande:

select
pid,
(select count(*) from comments where pid=c.pid) as antalet
from comments c
order by antalet desc

Det kan vara snabbare än group by förutsatt att du har bra indexering..

Får samma resultat:
Kod:

40
40
40
40
40
osv....

Känns som jag gör fel?
PHP-kod:

$sql "select 
pid,
(select count(*) from comments where pid=c.pid) as antalet
from comments c
order by antalet desc"
;
while(
$line mysql_fetch_assoc(mysql_query($sql))){
echo 
$line['pid'];
echo 
"<br>";


Är allting rätt när jag skriver ut resultatet?

obe 2009-12-03 17:59

select a.*, count(*) as ncomments from artiklar a left join comments c on c.pid=a.pid group by a.pid order by a.pid desc

??

Magnus_A 2009-12-03 20:30

Citat:

Ursprungligen postat av youheardit (Inlägg 20333909)
$sql = "select count(pid) as antalet,
pid
from comments
group by pid";
while($line = mysql_fetch_assoc(mysql_query($sql))){
echo $line['pid'];
echo "<br>";
}
?>[/CODE]
pid = postid som i förra posten...

Resultatet blir en oändligt lång lista med samma pid som i första kommentaren...
Kod:

40
40
40
40
40
osv....

har jag gjort fel ? eller är mysql-frågan fel ställd?

tack! :)

har jag gjort fel? you bet.
Gör du på detta viset så ställer du frågan till databasen om och om igen och visar resultatet för första raden ett oändligt antal gånger.
Den sql-fråga du fått ger det riktiga svaret, OM du ställer frågan rätt till databasen och sen tar reda på svaret och skriver ut det ordentligt.
Pröva med att ställa frågan En(1) gång till databasen, ta hand om resultatet och lista det på ett riktigt sätt:
Citat:

(fråga som ovan)
$result=mysql_query($sql);
while($line = mysql_fetch_assoc($result)){
print_r($line);
echo "<br>";
}
Ser du skillnaden?

obe 2009-12-04 00:03

Citat:

Ursprungligen postat av Magnus_A (Inlägg 20333949)
har jag gjort fel? you bet.
Gör du på detta viset så ställer du frågan till databasen om och om igen och visar resultatet för första raden ett oändligt antal gånger.
Den sql-fråga du fått ger det riktiga svaret, OM du ställer frågan rätt till databasen och sen tar reda på svaret och skriver ut det ordentligt.
Pröva med att ställa frågan En(1) gång till databasen, ta hand om resultatet och lista det på ett riktigt sätt:

Ser du skillnaden?

Dock är jag ganska övertygad om att mitt sätt är snabbare, dessutom får du även ut artikeldatan i samma fråga :)

Bjorne 2009-12-04 01:08

Ditt sätt är dock felaktigt. Tänk på vad som händer ifall en artikel har 0 kommentarer.

youheardit 2009-12-04 08:29

Magnus_A: Tack så mycket, detta var klockrent! :)

Obe: Som bjorne säger så är ju det problemet att alla artiklar (43955st) som inte har kommentar skrivs också ut. vilket jag inte vill, jag var nog lite otydlig i min första tråd, ber om ursäkt isåfall. men tack ändå :)

obe 2009-12-04 10:45

Citat:

Ursprungligen postat av Bjorne (Inlägg 20333985)
Ditt sätt är dock felaktigt. Tänk på vad som händer ifall en artikel har 0 kommentarer.

Ok, men en WHERE-sats är ju inte så svårt att lägga till. Generellt sett är joins bättre än subquerys.

Bjorne 2009-12-04 11:34

Det hjälper inte med en WHERE sats, trust me. :) Med LEFT JOIN:en kommer 1 rad för varje artikel att väljas för alla artiklar som har 0 eller 1 kommentar. Alltså kommer COUNT(*) ge 1 de fallen. Man kan lösa det genom att använda en INNER JOIN istället som gör att bara artiklar som har 1 eller flera kommetarer väljs. Men då listas ju inga artiklar med 0 kommentarer.

FredrikMH 2009-12-04 11:53

Bjorne, jo men det går att lösa. Fast det kanske är långsamt?

SELECT a.*, c.ncomments FROM artiklar a
LEFT JOIN (SELECT pid, count(*) AS ncomments FROM comments GROUP BY pid) AS c
ON c.pid=a.pid

Hur som helst så innebär en kombination av GROUP BY och ORDER BY att en temporär tabell skapas. Det bästa hade varit att spara antalet kommentarer i en egen kolumn i tabellen för artiklarna.

obe 2009-12-04 12:06

Citat:

Ursprungligen postat av Bjorne (Inlägg 20334038)
Det hjälper inte med en WHERE sats, trust me. :) Med LEFT JOIN:en kommer 1 rad för varje artikel att väljas för alla artiklar som har 0 eller 1 kommentar. Alltså kommer COUNT(*) ge 1 de fallen. Man kan lösa det genom att använda en INNER JOIN istället som gör att bara artiklar som har 1 eller flera kommetarer väljs. Men då listas ju inga artiklar med 0 kommentarer.

Ok, jag var tvungen att prova den och den fungerar. :) Du missade nog "GROUP BY".

Magnus_A 2009-12-04 21:57

Citat:

select count(kommentartabellen.postid) as antal_kommentarer,
kommentartabellen.postid,
en_annan_tabell.annat_fält
from kommentartabellen, en_annan_tabell
where kommentartabellen.postid=en_annan_tabell.postid
group by kommentartabellen.postid
order by antal_kommentarer desc limit [antal i topplistan]
Bättre så?

FredrikMH 2009-12-05 05:54

Den bästa lösningen är ändå att köra en seperat kolumn i artikel-tabellen och räkna antalet kommentarer där. Blir ju en extra SQL-fråga vid in/borttagning av kommentar men slipper köra en GROUP BY/ORDER BY.

Bjorne 2009-12-05 15:59

Citat:

Ursprungligen postat av FredrikMH (Inlägg 20334044)
Bjorne, jo men det går att lösa. Fast det kanske är långsamt?

SELECT a.*, c.ncomments FROM artiklar a
LEFT JOIN (SELECT pid, count(*) AS ncomments FROM comments GROUP BY pid) AS c
ON c.pid=a.pid

Hur som helst så innebär en kombination av GROUP BY och ORDER BY att en temporär tabell skapas. Det bästa hade varit att spara antalet kommentarer i en egen kolumn i tabellen för artiklarna.

Jo fast om man ska vara petnoga (vilket jag tycker man ska vara när det gäller sql) ska det vara:

SELECT a.*, COALESCE(c.ncomments, 0) FROM ...

Annars får du NULL istället för 0 ifall en artikel inte har några kommentarer. Men sen specificierade ju youheardit att topplistan aldrig ska innehålla artiklar med 0 kommentarer och då är ju obes ursprungliga version effektivast igen.


Alla tider är GMT +2. Klockan är nu 19:51.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson