Προς το περιεχόμενο

Πρόβλημα σε PHP, MySQL!! Advanced Topic!


DarkAge2

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπέρα σας,

 

1η φορά μπαίνω στο φόρουμ! :-D Ελπίζω να βρώ την βοήθεια σας γι'αυτο που θέλω.

 

Λοιπόν...

 

Έχω ενα mysql table με όνομα users στον οποιό έχω 3 fields [ ID , NAME , SCORE ] (παραπάνω ειναι απλά για ευκολία βάζω 3).

 

Θα το αναφέρω ως παράδειγμα για να ειναι πιο εύκολο και κατανοητό αυτό που ζητάω.

 

1. Μπαίνω στην σελίδα stats.php

2. Στον πίνακα users, εχω 100 εγγραφές.

3. Παίρνοντας το SESSION του χρήστη θέλω να μου κάνει το paging ανά 10 χρήστες(10 παίκτες σε 10 σελίδες / 100 σύνολο ) (Order By score + Limit ) στην σελίδα stats.php ΜΕ ΤΗΝ ΔΙΑΦΟΡΑ οτι θέλω αυτόματα να επιλέγεται η σελίδα που δείχνει τον τρέχων κάθε φορά χρήστη.

 

Για παράδειγμα εαν το score μου ειναι 0, σημαίνει πως θα ειμαι στην 10η σελίδα την οποία θέλω να εμφανίζει αυτόματα και να μην ψάχνει ο χρήστης.

Εαν το score μου ειναι για παράδειγμα 500 που ειναι ενα μέσο score, θέλω να μου εμφανίζει την σελίδα π.χ 5 επιλεγμένη.

 

Αυτό έχει κανείς ιδέα πως μπορεί να γίνει με βέλτιστο δυνατό τρόπο ( δεν θέλω να κάνω select all records και μετά να το χωρίζω σε arrays ).

 

Σας ευχαριστώ πολύ.

 

:rolleyes:

Δημοσ.

Το μονο που μπορω να σκεφτώ τωρα και που θα εκανα ηταν να φτιαξω στο ερωτημα μια προσωρινη μεταβλητη

 

$q1= "select @rownum:=@rownum+1 ‘rank’, p.* from users u, (SELECT @rownum:=0) r order by score";

 

 

 

Το παραπανω query θα το εβαζα μεσα σε ενα αλλο select

 

$q2 = "select ...." . $q1 . "..." ;

 

οπου θα επερνα το id που ηθελα.. Ετσι θα ηξερα το rank! Απο το rank (rank/10) ακεραια διαιρεση παίρνεις τον αριθμό σελίδας απο 0 εως .... 10

 

απο εκει και περα εχεις τον αριθμο σελίδας εκτελεις το select query σου με limit selida*10 ,10 αν δε κανω λαθος και εισαι κομπλερ

Δημοσ.

Advanced topic? :rolleyes:

 

Λοιπόν για να κάνεις paging πρέπει να ξέρεις πόσοι είναι όλοι οι users. Αυτό το ξέρεις ήδη (SELECT COUNT(*) FROM users), ας το πούμε S.

 

Για να μάθεις ποιά είναι η θέση του τρέχοντα χρήστη (έστω με score MyScore), αρκεί το πολύ απλό SELECT COUNT(*) FROM users WHERE score < MyScore. Έστω ότι αυτό το query επιστρέφει N, αυτό σημαίνει ότι ο τρέχων χρήστης είναι στη θέση S - N στην κατάταξη.

 

Επομένως βρίσκεται στη σελίδα (S - N) / P όπου P είναι το μέγεθος της κάθε σελίδας (με τον τύπο που δίνω η αρίθμηση των σελίδων ξεκινάει από το μηδέν).

 

Σε περίπτωση που πολλοί users έχουν το ίδιο score ενδέχεται να υπάρξουν περιπλοκές. Π.χ. έστω 10 users στη σελίδα και ο 8ος μέχρι και τον 12o user έχουν το ίδιο score. Αν όλοι οι χρήστες είναι 20 το query θα σου επιστρέψει N = 8, αλλά αν από αυτό υπολογίσεις σελίδα 20 - 8 / 10 = 1 δε θα είσαι απαραίτητα μέσα -- ανάλογα με το δευτερεύον κριτήριο ταξινόμησης μπορεί να είναι και στη σελίδα 0.

 

Ο προφανής τρόπος να το λύσεις αυτό είναι να προσαρμόσεις το query για να συμπεριλαμβάνει και το δεύτερο κριτήριο ταξινόμησης. Αν π.χ. εμφανίζεις πρώτα ανα score descending και μετά ανα user id ascending θα πρέπει να δώσεις SELECT COUNT(*) FROM users WHERE score < MyScore AND id > MyUserId κ.ο.κ.

Δημοσ.

defacer και παλι πως ξερει πια σελίδα ειναι;Απλα υποθετει οτι καθε σελιδα εχει διαφορα σκορ 100. Και μπορει 50 να εχουν απο 100-300 και 2 να εχουν υψηλα σκορ..

Δημοσ.

Αυτό έχει κανείς ιδέα πως μπορεί να γίνει με βέλτιστο δυνατό τρόπο ( δεν θέλω να κάνω select all records και μετά να το χωρίζω σε arrays ).

Τι εννοείς να το χωρίζεις σε arrays; Ένα array/σελίδα;

Ένα array για όλα αρκεί. Στην ουσία θα είναι η μεταβλητή όπου θα αποθηκεύσεις το resultset από την query σου και καλώντας την mysql_fetch_array() προχωράς στην επόμενη εγγραφή του resultset.

 

Αυτό που σκέφτομαι εγώ είναι να κάνεις ένα

>select id, name, score from users
order by score desc, id asc

και να αποθηκεύσεις το αποτέλεσμα στο παραπάνω array. Από εκεί κάνοντας αναζήτηση (υποθέτω ότι το έχεις θέσει το id της βάσης ίδιο με το session id) στο array βρίσκεις το index, έστω 54. Η ακέραια διαίρεση σου δίνει τον αριθμό της σελίδας (54 div 10=5) και το mod (54%10=4) την ακριβή θέση μέσα στη σελίδα.

Εναλλακτικά για να βρεις τη θέση στη συνολική κατάταξη (στα 100) χρησιμοποίησε τον τρόπο του defacer.

 

Δεν ξέρω αν είναι ο πιο αποδοτικός τρόπος αλλά μπορεί να δώσει καμιά ιδέα. Τουλάχιστον χρησιμοποιεί ένα μόνο array. :-D

 

 

@ΠάρηςΓ

Αυτό με τη διαφορά σκορ 100 που λες πού βρίσκεται; Γιατί από το αρχικό post δεν κατάλαβα να λέει κάτι τέτοιο.

Δημοσ.

Για παράδειγμα εαν το score μου ειναι 0, σημαίνει πως θα ειμαι στην 10η σελίδα την οποία θέλω να εμφανίζει αυτόματα και να μην ψάχνει ο χρήστης.

Εαν το score μου ειναι για παράδειγμα 500 που ειναι ενα μέσο score, θέλω να μου εμφανίζει την σελίδα π.χ 5 επιλεγμένη.

 

Εδω δλδ 5 σελιδα 500-400; Αλλα οπως ειπα δεν παει ετσι

Δημοσ.

defacer και παλι πως ξερει πια σελίδα ειναι;Απλα υποθετει οτι καθε σελιδα εχει διαφορα σκορ 100. Και μπορει 50 να εχουν απο 100-300 και 2 να εχουν υψηλα σκορ..

 

Τι ακριβώς δεν κατάλαβες από αυτά που έγραψα; Στην απλή περίπτωση (που δεν υπάρχουν 2 χρήστες με το ίδιο σκορ), με ένα query βλέπεις πόσοι είναι όλοι οι χρήστες. Με ένα άλλο query βλέπεις πόσοι είναι πιο κάτω απο σένα. Άρα ξέρεις τη θέση σου στην κατάταξη, άρα ξέρεις σε ποιά σελίδα είσαι.

 

Στη σύνθετη περίπτωση δεν αλλάζει τίποτα, απλά το ORDER BY γίνεται πιο περίπλοκο (υπάρχουν κι άλλες λύσεις για να το χειριστείς αυτό αλλά νομίζω πως αυτή που έγραψα είναι η προτιμότερη).

Δημοσ.

LuckyLuke ο τροπος που εγραψες σιγουρα δουλευει ,απλα πιστευω πως δεν ειναι βελτιστος.. Δλδ αν ειχες 1000 users να μεταφερεις 1000 εγγραφες και να κανεις αναζητηση μεσα απο array της php ( και οχι μεσω sql που ειναι optimized με ευρετηριο btree συνηθως) και να εμφανισεις μονο 10 απο αυτα ειναι λιγο αργό.

 

Η μεθοδος του defacer τωρα που την ξαναειδα ειναι εξυπνη ομως δεν ειμαι σιγουρος αν δουλεψει στη περιπτωση που ειπε.(μπορει να μου διαφευγει κατι και να κανω λαθος)

SELECT COUNT(*) FROM users WHERE score < MyScore AND id > MyUserId | πως ξερεις οτι μικροτερα id δεν εχουν μικροτερο score;

 

ισως ετσι ; SELECT COUNT(*) FROM users WHERE score < MyScore ΟR (score=MyScore AND id > MyUserId )

 

 

Πιστευω πως ο τροπος που προτεινα δεν εχει το παραπανω θεμα..

 

Τι ακριβώς δεν κατάλαβες από αυτά που έγραψα; Στην απλή περίπτωση (που δεν υπάρχουν 2 χρήστες με το ίδιο σκορ), με ένα query βλέπεις πόσοι είναι όλοι οι χρήστες. Με ένα άλλο query βλέπεις πόσοι είναι πιο κάτω απο σένα. Άρα ξέρεις τη θέση σου στην κατάταξη, άρα ξέρεις σε ποιά σελίδα είσαι.

 

Στη σύνθετη περίπτωση δεν αλλάζει τίποτα, απλά το ORDER BY γίνεται πιο περίπλοκο (υπάρχουν κι άλλες λύσεις για να το χειριστείς αυτό αλλά νομίζω πως αυτή που έγραψα είναι η προτιμότερη).

 

Δεν ειχα δει το count (το ειχα δει βραδυ και νυσταζα).

Δημοσ.

ισως ετσι ; SELECT COUNT(*) FROM users WHERE score < MyScore ΟR (score=MyScore AND id > MyUserId )

 

Πολύ σωστός. :)

 

Ο τρόπος που πρότεινες έχει επίσης το παραπάνω θέμα, νομίζω είναι προφανές.

 

>$q1= "select @rownum:=@rownum+1 ‘rank’, p.* from users u, (SELECT @rownum:=0) r order by score";

 

Αφού ORDER BY score είναι σα να λες "η σειρά με την οποία εμφανίζονται οι χρήστες που έχουν το ίδιο score δε με ενδιαφέρει" (άρα δε μπορείς και να την προβλέψεις). Τελείως θεωρητικά, αν δώσεις πρώτα αυτό και μετά το SELECT FROM users ... ORDER BY score LIMIT x, 10 η βάση μπορεί να σου επιστρέψει τις rows με διαφορετική σειρά από αυτή που χρησιμοποίησε για να βγάλει το rownum. Άρα μπορεί (στη θεωρία πάντα) να καταλήξεις να εμφανίζεις page όπου ο τρέχων χρήστης δεν είναι μέσα.

Δημοσ.

Το πρώτο κομάτι αλλάζει εβαλα το id για παραδειγμα οποτε ταξινομουνται βαση score και id.

 

$q1= "select @rownum:=@rownum+1 ‘rank’, p.* from users u, (SELECT @rownum:=0) r order by score,id";

 

Oσο για το δευτερο και ο δικος σου τροπος εχει το ιδιο θεμα. Δε ξερεις τι θα μεσολαβησει .Δλδ μπορει να παει σε αλλη σελιδα οπως εμενα...

 

Αυτο σπανιο μου φαινεται να συμβει και γκαντεμικο ,ισως με καποιο τροπο κλειδώματος-δοσοληψιων να γινοταν δουλεια εγγυημενη..

Δημοσ.

Το πρώτο κομάτι αλλάζει εβαλα το id για παραδειγμα οποτε ταξινομουνται βαση score και id.

 

$q1= "select @rownum:=@rownum+1 ‘rank’, p.* from users u, (SELECT @rownum:=0) r order by score,id";

 

Oσο για το δευτερο και ο δικος σου τροπος εχει το ιδιο θεμα. Δε ξερεις τι θα μεσολαβησει .Δλδ μπορει να παει σε αλλη σελιδα οπως εμενα...

 

Αυτο σπανιο μου φαινεται να συμβει και γκαντεμικο ,ισως με καποιο τροπο κλειδώματος-δοσοληψιων να γινοταν δουλεια εγγυημενη..

 

Και με τις δύο προσεγγίσεις το θέμα με το ordering είναι το ίδιο: ή δίνεις κατάλληλο ordering ή διατρέχεις κίνδυνο να μη σου δουλέψει σωστά σε περίπτωση ισοβαθμίας. Αν δώσεις κατάλληλο ordering και οι δύο τρόποι δουλεύουν σωστά.

 

Απο κει και πέρα τα subquery με το rank είναι σίγουρα μια πρωτότυπη προσέγγιση αλλά νομίζω ότι δεν είναι η καλύτερη λύση (πιο περίπλοκη, απαιτεί full table scan για να δώσεις το ranking κλπ).

Δημοσ.

Πιθανον να ειναι βαρυτερο αν και δε νομιζω οτι θελει full table scan και μπορει να συμπιεστεί σε 1 query. Επισης σημασία εχει αν θελει καταταξη η οχι ο σχεδιαστης.Βεβαια για τοσες λιγες εγγραφες και καθολου optimization να εχει μια χαρα θα παει

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.

  • Δημιουργία νέου...