0

Ich habe den Rake-Task geschrieben, um eine postgreSQL-Abfrage durchzuführen. Die Aufgabe gibt ein Objekt der Klasse Result zurück.pgSQL-Abfrageergebnisse in Batches verarbeiten

Hier ist meine Aufgabe:

task export_products: :environment do 
    results = execute "SELECT smth IN somewhere" 
    if results.present? 
     results 
    else 
     nil 
    end 
end 

def execute sql 
    ActiveRecord::Base.connection.execute sql 
end 

Mein weiterer Plan ist die Ausgabe in Chargen aufgeteilt und diesen Chargen nacheinander in eine CSV-Datei speichern. Hier bleibe ich stecken. Ich kann mir nicht vorstellen, wie man die find_in_batches-Methode des ActiveRecord :: Batches-Moduls für PG :: Result aufruft.

Wie soll ich fortfahren?

Edit: Ich habe eine Legacy-SQL-Abfrage zu einem Legacy-Datenbank

+0

Gibt es einen bestimmten Grund, warum Sie keine Abfragen für Model verwenden, anstatt SQL-Abfragen explizit zu schreiben? –

+0

@Aakash Gupta Ich habe eine Legacy-SQL-Abfrage zu einer Legacy-Datenbank –

Antwort

0

Wenn man sich wie find_in_batches is implemented anschauen, werden Sie sehen, dass der Algorithmus im Wesentlichen ist:

  1. Erzwingen Sie die Abfrage durch bestellt werden der Primärschlüssel
  2. Fügen Sie der Abfrage eine LIMIT-Klausel hinzu, um sie an die Stapelgröße anzupassen.
  3. Führen Sie die modifizierte Abfrage von (2), um eine Charge zu erhalten.
  4. Tun Sie alles, was mit der Charge getan werden muss.
  5. Wenn der Stapel kleiner als die Stapelgröße ist, ist die unbegrenzte Abfrage erschöpft, also sind wir fertig.
  6. Erhalten Sie den maximalen primären Abfragewert (last_max) aus dem Stapel, den Sie in (3) erhalten.
  7. hinzufügen primary_key_column > last_max auf die Abfrage von (2) ‚s WHERE Klausel, die Abfrage erneut ausführen, und geht (4) zu treten.

ziemlich geradlinig und könnte mit etwas wie folgt umgesetzt werden:

def in_batches_of(batch_size) 
    last_max = 0 # This should be safe for any normal integer primary key. 
    query = %Q{ 
    select whatever 
    from table 
    where what_you_have_now 
     and primary_key_column > %{last_max} 
    order by primary_key_column 
    limit #{batch_size} 
    } 

    results = execute(query % { last_max: last_max }).to_a 
    while(results.any?) 
    yield results 
    break if(results.length < batch_size) 
    last_max = results.last['primary_key_column'] 
    results = execute(query % { last_max: last_max }).to_a 
    end 
end 

in_batches_of(1000) do |batch| 
    # Do whatever needs to be done with the `batch` array here 
end 

Wo, natürlich, primary_key_column und Freunde ersetzt wurden mit realen Werten.

Wenn Sie in Ihrer Abfrage keinen Primärschlüssel haben, können Sie eine andere Spalte verwenden, die gut sortiert und für Ihre Anforderungen einzigartig ist. Sie könnten anstelle des Primärschlüssels auch eine OFFSET-Klausel verwenden, die bei großen Ergebnismengen jedoch teuer werden kann.

+1

Ich habe in Regeln gelesen, dass ich kurze Kommentare wie "Danke" vermeiden sollte, aber ich möchte Ihnen immer noch danken. –

+0

Es stört mich ein bisschen Menschlichkeit hin und wieder unabhängig von den "Regeln". –