2016-09-26 1 views
1

Auf eine previous question stellte ich eine ähnliche Frage, die auf eine Hilfstabelle als Teil der Kriterien für die Aufteilung der Daten verließ. Es scheint, dass mein jetziges Ziel einfacher ist, aber ich konnte es nicht herausfinden.Zusammengesetzten Text basierend auf einem Kriterium

Angesichts der Tabelle:

CREATE TABLE conversations (id int, record_id int, is_response bool, text text); 
INSERT INTO conversations VALUES 
    (1, 1, false, 'in text 1') 
, (2, 1, true , 'response text 1') 
, (3, 1, false, 'in text 2') 
, (4, 1, true , 'response text 2') 
, (5, 1, true , 'response text 3') 
, (6, 2, false, 'in text 1') 
, (7, 2, true , 'response text 1') 
, (8, 2, false, 'in text 2') 
, (9, 2, true , 'response text 2') 
, (10, 2, true , 'response text 3'); 

Ich möchte den Text aggregieren basierend auf dem is_response Wert und geben die folgenden:

record_id | aggregated_text         | 
----------+---------------------------------------------------+ 
1   |in text 1 response text 1       | 
----------+---------------------------------------------------+ 
1   |in text 2 response text 2 response text 3   | 
----------+---------------------------------------------------+ 
2   |in text 1 response text 1       | 
----------+---------------------------------------------------+ 
2   |in text 2 response text 2 response text 3   | 

ich die folgende Abfrage habe versucht, aber es funktioniert nicht Um zwei Antworten hintereinander zu aggregieren, ist IE: is_response in einer Sequenz wahr.

SELECT 
    record_id, 
    string_agg(text, ' ' ORDER BY id) AS aggregated_text 
FROM (
    SELECT 
     *, 
     coalesce(sum(incl::integer) OVER (ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING),0) AS grp 
    FROM (
     SELECT *, is_response as incl 
     FROM conversations 
     ) c 
    ) c1 
GROUP BY record_id, grp 
HAVING bool_or(incl) 
ORDER BY max(id); 

Die Ausgabe meiner Abfrage kommt noch hinzu, eine weitere Zeile für die folgende is_response Zeile wie folgt:

record_id | aggregated_text         | 
----------+---------------------------------------------------+ 
1   |in text 1 response text 1       | 
----------+---------------------------------------------------+ 
1   |in text 2 response text 2       | 
----------+---------------------------------------------------+ 
1   |response text 3         | 
----------+---------------------------------------------------+ 
2   |in text 1 response text 1       | 
----------+---------------------------------------------------+ 
2   |in text 2 response text 2       | 
----------+---------------------------------------------------+ 
2   | response text 3         | 
----------+---------------------------------------------------+ 

Wie kann ich es beheben?

+0

Sieht so aus, als ob Sie eine Fensterfunktion für mich brauchen. – jpmc26

+0

Vielen Dank für Ihre Antwort, können Sie mit einem Codebeispiel helfen? –

+0

Habe gerade keine Zeit. Ich wollte Ihnen nur einen Anhaltspunkt geben, um etwas zu sehen. – jpmc26

Antwort

1

Hier ist eine Variation der answer ich in Ihrem previous question gab:

SELECT record_id, string_agg(text, ' ') 
FROM (
    SELECT *, coalesce(sum(incl::integer) OVER w,0) AS subgrp 
    FROM (
     SELECT *, is_response AND NOT coalesce(lead(is_response) OVER w,false) AS incl 
     FROM conversations 
     WINDOW w AS (PARTITION BY record_id ORDER BY id) 
    ) t 
    WINDOW w AS (PARTITION BY record_id ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) 
) t1 
GROUP BY record_id, subgrp 
HAVING bool_or(incl) 
ORDER BY min(id); 

Die Idee ist, dass wir für jede Zeile die nächste Zeile des gleichen Datensatzes mit Hilfe desbetrachtenFensterfunktion. Wenn diese Zeile nicht existiert oder is_response falsch ist, während die aktuelle is_response wahr ist, wählen wir diese Zeile aus und aggregieren alle vorherigen unbenutzten Werte von text.

Diese Abfrage stellt auch sicher, dass wenn die letzte Konversation unvollständig ist (was in Ihren Beispieldaten nicht passiert), wird sie weggelassen.

1

Dies ist im Grunde eine einfachere Version von your previous question.

SELECT record_id, string_agg(text, ' ') As context 
FROM (
    SELECT *, count(NOT is_response OR NULL) OVER (PARTITION BY record_id ORDER BY id) AS grp 
    FROM conversations 
    ORDER BY record_id, id 
    ) sub 
GROUP BY record_id, grp 
ORDER BY record_id, grp; 

Erzeugt genau das gewünschte Ergebnis mit einer einzigen Fensterfunktion in einer Unterabfrage und aggregiert dann.

Ausführliche Erklärung und Links in meiner Antwort auf Ihre letzte Frage:

+0

nur eine Sache, die Reihenfolge der Zeilen ist falsch –

+0

und es aggregiert nicht mehr als eine falsche is_response: was bedeutet, wenn es 2 "in Text" oder mehr hintereinander, es nur die zweite Aggregation –

+0

@ShlomiSchwartz: Weder von diesen Dingen ist in deiner Frage. Es scheint auch nicht sinnvoll zu sein, Zeilen zu aggregieren, die * keine * Antwort auf die vorherige Zeile haben. –

Verwandte Themen