Postgres FÜR LOOP

74

Ich versuche, 25 zufällige Stichproben von 15.000 IDs aus einer Tabelle zu erhalten. Anstatt jedes Mal manuell auf run zu drücken, versuche ich, eine Schleife zu erstellen. Was ich voll und ganz verstehe, ist nicht die optimale Verwendung von Postgres, aber es ist das Werkzeug, das ich habe. Das habe ich bisher:

for i in 1..25 LOOP
   insert into playtime.meta_random_sample
   select i, ID
   from   tbl
   order  by random() limit 15000
end loop
user2840106
quelle

Antworten:

153

Prozedurale Elemente wie Schleifen sind nicht Teil der SQL-Sprache und können nur innerhalb des Körpers einer prozeduralen Sprachfunktion , einer Prozedur (Postgres 11 oder höher) oder einerDOAnweisung verwendet werden, wenn solche zusätzlichen Elemente durch die jeweilige prozedurale Sprache definiert sind. Der Standardwert ist PL / pgSQL , es gibt jedoch auch andere .

Beispiel mit plpgsql:

DO
$do$
BEGIN 
   FOR i IN 1..25 LOOP
      INSERT INTO playtime.meta_random_sample
         (col_i, col_id)                       -- declare target columns!
      SELECT  i,     id
      FROM   tbl
      ORDER  BY random()
      LIMIT  15000;
   END LOOP;
END
$do$;

Für viele Aufgaben, die mit einer Schleife gelöst werden können, steht eine kürzere und schnellere satzbasierte Lösung vor der Tür. Reines SQL-Äquivalent für Ihr Beispiel:

INSERT INTO playtime.meta_random_sample (col_i, col_id)
SELECT t.*
FROM   generate_series(1,25) i
CROSS  JOIN LATERAL (
   SELECT i, id
   FROM   tbl
   ORDER  BY random()
   LIMIT  15000
   ) t;

Über generate_series():

Informationen zur Optimierung der Leistung zufälliger Auswahlen:

Erwin Brandstetter
quelle
7

Unten finden Sie ein Beispiel, das Sie verwenden können:

create temp table test2 (
  id1  numeric,
  id2  numeric,
  id3  numeric,
  id4  numeric,
  id5  numeric,
  id6  numeric,
  id7  numeric,
  id8  numeric,
  id9  numeric,
  id10 numeric) 
with (oids = false);

do
$do$
declare
     i int;
begin
for  i in 1..100000
loop
    insert into test2  values (random(), i * random(), i / random(), i + random(), i * random(), i / random(), i + random(), i * random(), i / random(), i + random());
end loop;
end;
$do$;
Gabriel
quelle
2

Ich bin gerade auf diese Frage gestoßen, und obwohl sie alt ist, dachte ich, ich würde eine Antwort für die Archive hinzufügen. Das OP fragte nach Schleifen, aber ihr Ziel war es, eine zufällige Stichprobe von Zeilen aus der Tabelle zu sammeln. Für diese Aufgabe bietet Postgres 9.5+ die TABLESAMPLE-Klausel für WHERE an. Hier ist ein guter Überblick:

https://www.2ndquadrant.com/de/blog/tablesample-in-postgresql-9-5-2/

Ich neige dazu, Bernoulli eher zeilenbasiert als seitenbasiert zu verwenden, aber die ursprüngliche Frage bezieht sich auf eine bestimmte Zeilenanzahl. Dafür gibt es eine eingebaute Erweiterung:

https://www.postgresql.org/docs/current/tsm-system-rows.html

CREATE EXTENSION tsm_system_rows;

Dann können Sie eine beliebige Anzahl von Zeilen abrufen:

select * from playtime tablesample system_rows (15);
Morris de Oryx
quelle
1

Ich finde es bequemer, eine Verbindung mit einer prozeduralen Programmiersprache (wie Python) herzustellen und diese Art von Abfragen durchzuführen.

import psycopg2
connection_psql = psycopg2.connect( user="admin_user"
                                  , password="***"
                                  , port="5432"
                                  , database="myDB"
                                  , host="[ENDPOINT]")
cursor_psql = connection_psql.cursor()

myList = [...]
for item in myList:
  cursor_psql.execute('''
    -- The query goes here
  ''')

connection_psql.commit()
cursor_psql.close()
LoMaPh
quelle