8

Ich habe die Situation:Postgres: links, indem sie mit, um beizutreten und begrenzen 1

Table1 has a list of companies. 
Table2 has a list of addresses. 
Table3 is a N relationship of Table1 and Table2, with fields 'begin' and 'end'. 

Da Unternehmen im Laufe der Zeit bewegen kann, ein LEFT JOIN unter ihnen Ergebnisse in mehreren Datensätzen für jedes Unternehmen.

begin und end Felder sind nie NULL. Die Lösung, um die neueste Adresse zu finden, ist eine ORDER BY being DESC, und ältere Adressen zu entfernen ist ein LIMIT 1.

Das funktioniert gut, wenn die Abfrage nur 1 Firma bringen kann. Aber ich brauche eine Abfrage, die alle Table1-Datensätze mit ihren aktuellen Table2-Adressen verknüpft. Daher muss die Entfernung veralteter Daten (AFAIK) in der ON-Klausel von LEFT JOIN erfolgen.

Irgendeine Idee, wie ich die Klausel bauen kann, um doppelte Table1 Firmen nicht zu schaffen und letzte Adresse zu holen?

Antwort

3

schaffte ich es mit dem Windows-Funktion zu lösen:

für jeden Datensatz
WITH ranked_relationship AS(
    SELECT 
     * 
     ,row_number() OVER (PARTITION BY fk_company ORDER BY dt_start DESC) as dt_last_addr 
    FROM relationship 
) 

SELECT 
    company.* 
    address.*, 
    dt_last_addr as dt_relationship 
FROM 
    company 
    LEFT JOIN ranked_relationship as relationship 
      ON relationship.fk_company = company.pk_company AND dt_last_addr = 1 
    LEFT JOIN address ON address.pk_address = relationship.fk_address 

row_number() erzeugt einen int-Zähler, innen Jedes Fenster basiert auf fk_company. Für jedes Fenster kommt der Datensatz mit dem spätesten Datum zuerst mit Rang 1, dann stellt dt_last_addr = 1 sicher, dass der JOIN nur einmal für jeden fk_company passiert, mit dem Datensatz mit der letzten Adresse.

Fensterfunktionen sind sehr leistungsfähig und wenige ppl verwenden sie, sie vermeiden viele komplexe Joins und Unterabfragen!

9

Verwenden Sie eine abhängige Unterabfrage mit der Funktion max() in einer Join-Bedingung.
So etwas wie in diesem Beispiel:

SELECT * 
FROM companies c 
LEFT JOIN relationship r 
ON c.company_id = r.company_id 
    AND r."begin" = (
     SELECT max("begin") 
     FROM relationship r1 
     WHERE c.company_id = r1.company_id 
    ) 
INNER JOIN addresses a 
ON a.address_id = r.address_id 

Demo: http://sqlfiddle.com/#!15/f80c6/2

+0

Schön auf sqlfiddle - Ich habe bis jetzt nur jfiddle gesehen, aber sqlfiddle scheint super hilfreich! – dwanderson