J'ai la situation:
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'.
Étant donné que les entreprises peuvent évoluer au fil du temps, une jointure à gauche parmi elles entraîne plusieurs enregistrements pour chaque entreprise.
Les champs begin
et end
ne sont jamais NULL. La solution pour trouver la dernière adresse est d'utiliser un ORDER BY being DESC
, et pour supprimer les anciennes adresses est un LIMIT 1
.
Cela fonctionne bien si la requête ne peut amener qu'une seule entreprise. Mais j'ai besoin d'une requête qui apporte tous les enregistrements Table1, joints à leurs adresses Table2 actuelles. Par conséquent, la suppression des données obsolètes doit être effectuée (AFAIK) dans la clause ON de LEFT JOIN.
Une idée comment je peux construire la clause pour ne pas créer de sociétés Table1 dupliquées et apporter la dernière adresse?
J'ai réussi à le résoudre en utilisant la fonction Windows:
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 () crée un compteur int pour chaque enregistrement, à l'intérieur de chaque fenêtre basée sur fk_company. Pour chaque fenêtre, l'enregistrement avec la dernière date vient d'abord avec le rang 1, puis dt_last_addr = 1
s'assure que le JOIN ne se produit qu'une seule fois pour chaque fk_company
, avec l'enregistrement avec la dernière adresse.
Les fonctions de fenêtre sont très puissantes et peu de personnes les utilisent, elles évitent de nombreuses jointures et sous-requêtes complexes!
Utilisez une sous-requête dépendante avec la fonction max () dans une condition de jointure.
Quelque chose comme dans cet exemple:
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