Frage

Wie wähle ich eine (oder eine) beliebige Zeile (n) aus einer Tabelle mit SQLAlchemy?

War es hilfreich?

Lösung

Das ist sehr viel ein Datenbank-spezifisches Problem.

Ich weiß, dass PostgreSQL, SQLite, MySQL und Oracle die Möglichkeit haben, durch eine Zufallsfunktion, um zu bestellen, so können Sie dies in SQLAlchemy verwenden können:

from  sqlalchemy.sql.expression import func, select

select.order_by(func.random()) # for PostgreSQL, SQLite

select.order_by(func.rand()) # for MySQL

select.order_by('dbms_random.value') # For Oracle

Als nächstes müssen Sie die Abfrage durch die Anzahl der Datensätze begrenzen Sie (zB mit .limit()) benötigen.

Beachten Sie, dass zumindest in PostgreSQL, die Auswahl zufällig Rekord schweren Perfomance Probleme hat; hier ist guter Artikel über sie.

Andere Tipps

Wenn Sie die ORM verwenden und die Tabelle ist nicht groß (oder Sie haben ihre Menge der Zeilen im Cache) und Sie wollen es, unabhängig sein Datenbank der wirklich einfachen Ansatz ist.

import random
rand = random.randrange(0, session.query(Table).count()) 
row = session.query(Table)[rand]

Das ist Betrug leicht, aber das ist, warum Sie ein ORM verwenden.

Es gibt eine einfache Möglichkeit, eine beliebige Zeile zu ziehen, die Datenbank unabhängig ist. verwenden .Offset Just (). Keine Notwendigkeit, alle Zeilen zu ziehen:

import random
query = DBSession.query(Table)
rowCount = int(query.count())
randomRow = query.offset(int(rowCount*random.random())).first()

Wo Tabelle Tisch (oder könnten Sie irgendeine Frage stellen dort). Wenn Sie ein paar Zeilen wollen, dann können Sie ihn nur mehrere Male ausgeführt, und stellen Sie sicher, dass jede Zeile mit dem vorherigen identisch ist.

Hier vier verschiedene Variationen, bestellt von langsamsten schnellsten. timeit Ergebnisse am unteren Rand:

from sqlalchemy.sql import func
from sqlalchemy.orm import load_only

def simple_random():
    return random.choice(model_name.query.all())

def load_only_random():
    return random.choice(model_name.query.options(load_only('id')).all())

def order_by_random():
    return model_name.query.order_by(func.random()).first()

def optimized_random():
    return model_name.query.options(load_only('id')).offset(
            func.floor(
                func.random() *
                db.session.query(func.count(model_name.id))
            )
        ).limit(1).all()

timeit Ergebnisse für 10.000 Läufe auf meinem Macbook gegen eine PostgreSQL-Tabelle mit 300 Zeilen:

simple_random(): 
    90.09954111799925
load_only_random():
    65.94714171699889
order_by_random():
    23.17819356000109
optimized_random():
    19.87806927999918

Sie können leicht erkennen, dass func.random() mit weit schneller als alle Ergebnisse Pythons random.choice() zurück.

Darüber hinaus, da die Größe der Tabelle steigt, wird die Leistung der order_by_random() erheblich verschlechtern, weil ein ORDER BY eine vollständige Tabelle gegenüber dem COUNT in optimized_random() scannen erfordert kann einen Index verwenden.

Einige SQL DBMS, nämlich Microsoft SQL Server, DB2 und PostgreSQL SQL implementiert haben: 2003 TABLESAMPLE Klausel. Unterstützung wurde hinzugefügt, um SQLAlchemy in Version 1.1 . Es ermöglicht eine Probe einer Tabelle zurückkehr verschiedene Probenahmeverfahren verwendet. - Der Standard erfordert SYSTEM und BERNOULLI, die eine gewünschte ungefähre Prozentsatz einer Tabelle zurück

In SQLAlchemy FromClause.tablesample() und tablesample() verwendet ein TableSample Konstrukt zu produzieren:

# Approx. 1%, using SYSTEM method
sample1 = mytable.tablesample(1)

# Approx. 1%, using BERNOULLI method
sample2 = mytable.tablesample(func.bernoulli(1))

Es gibt eine leichte Gotcha, wenn sie mit kartiert Klassen verwendet: das erzeugte TableSample Objekt muss, um Alias-Bezeichnung verwendet werden Modellobjekte abzufragen:

sample = aliased(MyModel, tablesample(MyModel, 1))
res = session.query(sample).all()

Da viele der Antworten Performance-Benchmarks enthalten, werde ich einige einfache Tests auch hier enthalten. Mit Hilfe einer einfachen Tabelle in PostgreSQL mit etwa einer Million Zeilen und einer einzigen Integer-Spalte, wählen Sie (ca..) 1% Beispiel:

In [24]: %%timeit
    ...: foo.select().\
    ...:     order_by(func.random()).\
    ...:     limit(select([func.round(func.count() * 0.01)]).
    ...:           select_from(foo).
    ...:           as_scalar()).\
    ...:     execute().\
    ...:     fetchall()
    ...: 
307 ms ± 5.72 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [25]: %timeit foo.tablesample(1).select().execute().fetchall()
6.36 ms ± 188 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [26]: %timeit foo.tablesample(func.bernoulli(1)).select().execute().fetchall()
19.8 ms ± 381 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

Vor rauschen SYSTEM Probenahmeverfahren zu verwenden, soll man wissen, dass es Proben Seiten , nicht einzelnes Tupel, so dass es nicht für kleine Tische geeignet sein könnte, zum Beispiel.

Dies ist die Lösung, die ich verwende:

from random import randint

rows_query = session.query(Table)                # get all rows
if rows_query.count() > 0:                       # make sure there's at least 1 row
    rand_index = randint(0,rows_query.count()-1) # get random index to rows 
    rand_row   = rows_query.all()[rand_index]    # use random index to get random row

Dies ist meine Funktion zufällige Zeilen (n) aus einer Tabelle auswählen:

from sqlalchemy.sql.expression import func

def random_find_rows(sample_num):
    if not sample_num:
        return []

    session = DBSession()
    return session.query(Table).order_by(func.random()).limit(sample_num).all()

Diese Lösung wird eine einzelne zufällige Zeile auswählen

Diese Lösung setzt voraus, dass die Primärschlüssel-ID genannt wird, soll es sein, wenn sie nicht schon:

import random
max_model_id = YourModel.query.order_by(YourModel.id.desc())[0].id
random_id = random.randrange(0,max_model_id)
random_row = YourModel.query.get(random_id)
print random_row

Theres ein paar Möglichkeiten, durch SQL, je nachdem, welche Datenbank verwendet wird.

(ich glaube, SQLAlchemy all diese verwenden können, sowieso)

mysql:

SELECT colum FROM table
ORDER BY RAND()
LIMIT 1

PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1

MSSQL:

SELECT TOP 1 column FROM table
ORDER BY NEWID()

IBM DB2:

SELECT column, RAND() as IDX
FROM table
ORDER BY IDX FETCH FIRST 1 ROWS ONLY

Oracle:

SELECT column FROM
(SELECT column FROM table
ORDER BY dbms_random.value)
WHERE rownum = 1

Allerdings weiß ich nicht, von jedem Standard-Weg

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top