Zufälligen Datensatz selektieren



  • Hallo!
    mit

    SELECT spalte FROM tabelle ORDER BY RAND()
    

    kann ich einen zufälligen Datensatz auswählen.
    Nun habe ich der Tabelle eine int-Spalte hinzugefügt. Da wird eine zahl abgespeichert. Mit dieser zahl möchte ich die wahrscheinlichkeit, dass ein datensatz ausgewählt wird erhöhen. Also je höher die zahl desto wahrscheinlicher.
    Nun kann ich entweder eine Tabelle generieren die jeden datensatz so oft enthält wie in meiner int-Spalte angegeben oder in meiner sql anweisung irgendwie eine Virtuelle tabelle generieren und aus ihr die Datensätze selectieren. geht sowas?
    Oder allgemeiner: kann man mit select die Zeilen vervielfacht auswählen?



  • Geht sicher, aber ich glaub ich würds einfach über php machen.
    Beim einlesen direkt in ein array und die einträge quasi mit deiner int spalte multipizieren. Und dann mit der random funktion von php eins zufällig wählen.



  • Ja da muss man aber dann erst die ganze tabelle einlesen und verarbeiten. wird das nicht perfomanter es mit sql zu erledigen?



  • Naja dein ausdruck ließt ja eh die ganze spalte.
    ORDER BY RAND() gibts doch auch garnicht. ASC oder DESC.

    Ich glaube du meinst sowas wie WHERE id = RAND(); oder sowas...
    wenn du eine spalte priorität hast kannst vllt iwie sowas machen:

    WHERE priority > RAND().

    Aus dem gewählten dann noch mal mit id=RAND() eine raussuchen...

    Wie genau das geht weiß ich nicht. Denke mal über subselects.
    Auch wie man mit RAND() genau arbeitet weiß ich nicht.

    Hast du deine zeile mal gestestet?



  • Sqwan schrieb:

    Naja dein ausdruck liest ja eh die ganze spalte.
    ORDER BY RAND() gibts doch auch garnicht.

    Viele DBS geben die Möglichkeit nach der Spaltennummer zu sortiern. Also

    SELECT a,b,c FROM t ORDER BY 2
    

    heißt dann nach b zu sortieren. Dadurch entsteht der zufällige Eindruck. Besser wäre sowas wie

    SELECT * FROM t LIMIT 1 START RAND()
    

    (Die genaue Syntax ist DBS-spezifisch). Wobei wohl der RND-Wert nicht größer als die Zeilenanzahl sein sollte.
    @OP: Wenn Du Zeilen verdoppeln willst könntest du dich mit einem Kreuzprodukt versuchen. Nehmen wir mal an es gibt 10 Prioritäten:

    CREATE TABLE mult (v integer);
    INSERT INTO mult (1);
    INSERT INTO mult (2);
    INSERT INTO mult (3);
    INSERT INTO mult (4);
    INSERT INTO mult (5);
    INSERT INTO mult (6);
    INSERT INTO mult (7);
    INSERT INTO mult (8);
    INSERT INTO mult (9);
    INSERT INTO mult (10);
    

    Deine Tabelle besitzt eine Spalte prioritaet. Dann vllt (ungetestet)

    SELECT mytable.* FROM mytable,mult WHERE mult.v <= mytable.prioritaet
    


  • pseudocode:

    float i = rand();
    query = "select * from tabelle where priorität*"+i+">1 order by rand() limit 1";
    

    mfg
    xXx



  • ich denk ich würd eher subselects nehmen und dann via LIMIT eine zeile rausziehen

    edit: sortieren kann da richtig langsam sein wenn kein index drauf ist und dieser müsste ja dann beim vorherigen beispiel auf alle spalten sein was totaler schrott ist 👎

    verwendets doch mal zum testen größere tabellen so ab 500mb dann klappts auch mit dem nachbarn



  • Hi,

    neoexpert schrieb:

    Hallo!
    mit

    SELECT spalte FROM tabelle ORDER BY RAND()
    

    kann ich einen zufälligen Datensatz auswählen.
    Nun habe ich der Tabelle eine int-Spalte hinzugefügt. Da wird eine zahl abgespeichert. Mit dieser zahl möchte ich die wahrscheinlichkeit, dass ein datensatz ausgewählt wird erhöhen. Also je höher die zahl desto wahrscheinlicher.

    Um wieviel wahrscheinlicher ist es denn, dass eine eine Zeile mit prio = 3 gegenüber eine Zeile mit prio = 1 ausgewählt wird? Dreimal so wahrscheinlich? Und ggü. prio = 2 eineinhalb mal so wahrscheinlich?

    Mir schwirren da zwei Ansätze im Kopf rum.
    a) Du kannst IMHO über prio*RAND() sortieren
    b) Der mathematische Ansatz:
    Seien die Prioritäten p_1 bis p_n
    Die Wahrscheinlichkeit, dass eine bestimmte Spalte i ausgewählt wird, ist also
    p_i / (p_1 + ... + p_n) (diesen Ausdruck definiere ich mal als P_i. Er ist normalisiert ggü. allen Prioritäten)

    Eigentlich willst du nun eine Zufallszahl X ziehen, und dann schauen
    Wenn 0 <= X < P_1, dann nimm Zeile 1
    Wenn P_1 <= X < P_1+P_2, dann nimm Zeile 2
    Wenn P_1 + P_2 <= X < P_2, dann nimm Zeile 2
    ...
    Wenn Summe(P_j, j=1..i-1) <= X < Summe(P_j, j=1..i), dann nimm Zeile i
    ...
    Wenn P_(n-1) <= X <= 1, dann nimm Zeile n

    Dazu müsstest du dann allerdings eine Stored-Procedure (SP) schreiben, um das ordentlich zu lösen (die müsste, grob gesagt, die Zufallszahl (ZF) berechnen (vor deinem Statement, nicht in der SP, weil du ja nur eine ZF haben willst), und dann 1 zurückgeben, wenn die übergebene Zeile die ausgewählte Zeile ist, ansonsten 0. Ich befürchte, dass würde nicht ohne Subrequests funktionieren, da du in der SP tatsächlich alle Prioritäten brauchst).

    Gruß, MJM



  • sauber löst man das nur mit einer ("denormalisierten" das eher das falsche wort) tabelle...

    +-+
    |a|
    |a|
    |b|
    +-+

    und wieviel öfter zieh ich jetzt a statt b 😕



  • ja genau so wollte ich das machen. Kann man irgendwie so eine Tabelle mit SQL basteln? In meiner int-spalte ist dabei die anzahl der gewünschten zeilen gespeichert.



  • deine int spalte bekommst dann mit nem group by... aber nein so einfach geht das nicht. entweder das script oder eine stored procedure kommt aber auch darauf an wennst häufig deine prioritäten änderst kannst das natürlich vergessen...



  • no_code schrieb:

    +-+
    |a|
    |a|
    |b|
    +-+

    Geht das mit SQL aus einer tabelle
    +-+-+
    |a|2|
    |b|1|
    +-+-+
    die Zeilen zu vervielfachen? Die zweite spalte ist dabei der Faktor um den vervielfacht wird.
    +-+
    |a|
    |a|
    |b|
    +-+



  • kommt auf deine datenbank an. ohne stored procedures denke ich nein



  • statt die ganzen zeilen kannst auch ne 2. tabelle nehmen in der nur die ids für die erste tabelle liegen dann hast auch nicht nen ganz so großen overhead...

    so wars gedacht...
    +-+-+-+
    |1|a|2|
    |2|b|1|
    +-+-+-+

    +-+
    |1|
    |1|
    |2|
    +-+

    naja viel spaß beim frickeln 😃


Anmelden zum Antworten