2016-05-24 8 views
0

Ich habe eine Tabelle namens fragments, die eine Reihe von Wörtern und Satzfragmente enthalten. Ich möchte einen zufälligen "Satz" erstellen, indem ich ein zufälliges Fragment an die von mir erstellte Zeichenfolge angehängt habe (getrennt durch ein Trennzeichen). Ich möchte dies solange tun, bis ich eine bestimmte Länge erreicht habe, und dann die resultierende Zeichenfolge zurückgeben. Was ist der beste Weg, dies in PostgreSQL zu tun?Erstellen Semi-Random String aus Tabelle in PostgreSQL

id | text 
---------------- 
1 | hello 
2 | world 

das Beispiel oben angegebene Tabelle und eine gewünschte Länge von 20 Ich mag, um wieder etwas erwarten würde:

world hello hello world 

http://sqlfiddle.com/#!15/0a88ca/1

Antwort

1

Sie könnten einen rekursiven CTE für diesen Einsatz:

WITH RECURSIVE recCte (sentence, length) AS 
(
     --recursive seed 
     SELECT 
     CAST("text" AS VARCHAR(200)) as sentence, 
     1 as length 
     FROM (SELECT "text" FROM test.fragments ORDER BY random() LIMIT 1)frag 

     UNION ALL 

     --recursive term 
     SELECT 
      CAST(recCTE.sentence || ' ' || frag.text as VARCHAR(200)), 
      recCTE.length + 1 
     FROM 
      reccte, (SELECT "text" from test.fragments ORDER BY random() LIMIT 1)frag 
     WHERE recCTE.length <= 20 --Sentence word length 
    ) 
    --Select the full sentence made 
    SELECT sentence FROM recCTE WHERE length = 20; 

Dies ist ein wenig beteiligt, aber es ist perfekt für Ihre Bedürfnisse. Eine rekursive CTE-Abfrage besteht aus drei Teilen.

  1. Der rekursive Seed - Dies ist der Teil der Abfrage, die nicht rekursiv ist. Es ist der Ausgangspunkt für die Abfrage. Wir greifen nur ein zufälliges Wort aus der Tabelle.
  2. Der rekursive Ausdruck - Dies ist der Teil der Abfrage, der rekursiv ist. Es bezieht sich auf sich selbst ...FROM recCTE .... Wir greifen wieder zufällig ein Wort aus dem Tisch und kleben es auf den Satz. Während wir dies tun, verfolgen wir, wie tief wir in den Iterationen sind, so dass wir nach 20 Schleifen anhalten können.
  3. Die endgültige Select-Anweisung, um den vollständigen Satz aus dem rekursiven CTE auszuwählen. Jede Iteration erstellt einen Datensatz, so dass wir uns den Datensatz nehmen, der ihn auf 20 gebracht hat. Ändern Sie "20" im rekursiven CTE und die finale Select-Anweisung, um die Länge des Satzes zu ändern.

editting eine Version hinzuzufügen, die Zeichenlänge verwendet:

Dies ist ein wenig komplizierter, weil wir ORDER BY random() LIMIT 1 zu bekommen einen zufälligen Text aus der Fragmente Tabelle verwenden, aber Sie können nicht ORDER BY und LIMIT in einem rekursiven CTE. Also immer genau 20 Zeichen ist schwierig, aber .. können wir < = 20 erhalten, die ganz in der Nähe ist:

WITH RECURSIVE recCte (sentence, length) AS 
    (
     SELECT 
     CAST("text" AS VARCHAR(200)) as sentence, 
     length("text") as length 
     FROM (SELECT "text" FROM test.fragments ORDER BY random() LIMIT 1)frag 

     UNION ALL 

     SELECT 
      CAST(cte.sentence || ' ' || frag.text as VARCHAR(200)), 
      cte.length + 1 + length(frag.text) 
     FROM 
      reccte cte, (SELECT text FROM test.fragments ORDER BY random() LIMIT 1) frag 
     WHERE 
     length(frag.text) < (20-cte.length) 
     AND cte.length <= 20 --Sentence word length 

    ) 

SELECT sentence, length FROM recCTE ORDER BY length DESC LIMIT 1; 

Die großen Änderungen hier ändern sich die Length Feld die Zeichenlänge zu berechnen und diese Einschränkung hinzuzufügen, in die WHERE Klausel des rekursiven Terms. Schließlich wir ORDER BY length DESC, um die CTE-Datensätze nach Zeichenlänge zu sortieren, und LIMIT 1, um die größte, die wir durch die Iterationen erstellt zu greifen.

+0

Super! Ich dachte, es wäre etwas in einer rekursiven Abfrage, aber ich war bei der Implementierung verloren. Danke für die ausführliche Antwort. –

Verwandte Themen