2016-12-22 6 views
1

Ich kann nicht herausfinden, wie man innerhalb der Gruppe begrenzen kann, obwohl ich alle ähnlichen Fragen hier gelesen habe. PSQL doc Lesen nicht helfen entweder :(Betrachten Sie das folgende:.Wie führe ich LIMIT innerhalb der GROUP in derselben Tabelle?

CREATE TABLE article_relationship 
(
    article_from INT NOT NULL, 
    article_to INT NOT NULL, 
    score INT 
); 

Ich möchte pro gegebenem Artikel IDs nach Punkten sortiert, um eine Liste der Top-5 in Verbindung stehende Artikel bekommen

Hier ist, was ich versucht:

select DISTINCT o.article_from 
from article_relationship o 
join lateral (
     select i.article_from, i.article_to, i.score from article_relationship i 
     order by score desc 
     limit 5 
     ) p on p.article_from = o.article_from 
where o.article_from IN (18329382, 61913904, 66538293, 66540477, 66496909) 
order by o.article_from; 

Und es gibt nichts zurück. ich unter Eindruck war, dass äußere Abfrage wie Schleife ist also denke ich, ich brauche nur Quell-IDs gibt.

auch was, wenn ich möchte aufbeitretenTabelle wo gibt es Spalten id und title und Titel der verwandten Artikel in Resultset erhalten?

Ich habe in innere Join-Abfrage:

select o.id, p.* 
from articles o 
join lateral (
     select a.title, i.article_from, i.article_to, i.score 
     from article_relationship i 
     INNER JOIN articles a on a.id = i.article_to 
     where i.article_from = o.id 
     order by score desc 
     limit 5 
     ) p on true 
where o.id IN (18329382, 61913904, 66538293, 66540477, 66496909) 
order by o.id; 

Aber es machte es sehr, sehr langsam.

+0

meinem vorherigen Kommentar kratzen, vollständig die Abfrage – JanR

+0

falsch verstanden --- Also Sie wollen die ersten 5 Punkte insgesamt ---, warum auch nicht rechts/links beitreten? (weiß nicht, wie man Text lol) –

+0

@SamuelJackson wegen der Sortierung nach Ergebnis innerhalb der Gruppe – expert

Antwort

1

Das Problem, dass keine Zeilen von Ihrer Abfrage zurückgegeben werden, ist, dass Ihre Join-Bedingung falsch ist: ; Dies sollte offensichtlich ON p.article_from = o.article_to sein.

Abgesehen von dieser Problemstellung gibt Ihre Abfrage nicht die fünf besten Scoring-Beziehungen pro Artikel-ID zurück. Stattdessen gibt es die Artikel-IDs zurück, die einen der 5 am besten bewerteten Artikel in der gesamten Tabelle referenzieren, und (auch) mindestens einen der 5 referenzierten Artikel, für die Sie die ID angeben.

Sie können die besten 5 bewerteten referenzierten Artikel pro referenzierendem Artikel mit einer Fensterfunktion erhalten, um die Punktzahlen in einer Unterauswahl zu ordnen und dann nur die obersten 5 in der Hauptabfrage auszuwählen. eine Liste der referenzierten Artikel IDs Angeben bedeutet effektiv, dass Sie zählen, wie diese referenzierten Artikel für jede Referenzierung Artikel bewertet:

SELECT article_from, article_to, score 
FROM (
    SELECT article_from, article_to, score, 
      rank() OVER (PARTITION BY article_from ORDER BY score DESC) AS rnk 
    FROM article_relationship 
    WHERE article_to IN (18329382, 61913904, 66538293, 66540477, 66496909)) a 
WHERE rnk < 6 
ORDER BY article_from, score DESC; 

Dies unterscheidet sich von Code, dass es für jeden article_from bis 5 Datensätze zurückgibt, aber es stimmt mit Ihrer ursprünglichen Beschreibung überein.

Hinzufügen von Spalten aus der Tabelle articles ist trivialerweise in der Hauptabfrage durchgeführt:

SELECT a.article_from, a.article_to, a.score, articles.* 
FROM (
    SELECT article_from, article_to, score, 
      rank() OVER (PARTITION BY article_from ORDER BY score DESC) AS rnk 
    FROM article_relationship 
    WHERE article_to IN (18329382, 61913904, 66538293, 66540477, 66496909)) a 
JOIN articles ON articles.id = a.article_to 
WHERE a.rnk < 6 
ORDER BY a.article_from, a.score DESC; 
+0

Danke, Patrick! Ich habe auch eine laterale Version gepostet, die ich letzte Nacht gefunden habe. Könntest du mir bitte deine Vor-/Nachteile deiner Version vs. In meinen Messungen ist deine Version ~ 15% schneller. – expert

+1

Ich bin froh, Ihnen helfen zu können. Ich kann jedoch nicht sagen, warum meine Version schneller wäre. Der Ansatz ist etwas anders und Änderungen der Geschwindigkeit können auch durch die Indexnutzung verursacht werden. Im Allgemeinen sind Fensterfunktionen jedoch sehr eng mit dem relationalen Datenmodell (Arbeit mit Sätzen) ausgerichtet, so dass diese Funktionen besser an die interne Struktur der Daten angepasst werden können.Aber selbst für erfahrene SQL-Entwickler ist Effizienz manchmal mehr eine schwarze Kunst als Wissenschaft! – Patrick

1

Version mit join lateral

select o.id as from_id, p.article_to as to_id, a.title, a.journal_id, a.pub_date_p from articles o 
    join lateral (
     select i.article_to from article_relationship i 
     where i.article_from = o.id 
     order by score desc 
     limit 5 
     ) p on true 
    INNER JOIN articles a on a.id = p.article_to 
where o.id IN (18329382, 61913904, 66538293, 66540477, 66496909) 
order by o.id; 
Verwandte Themen