2
votes

Comment joindre à gauche deux tables en fonction de la valeur la plus proche de leurs attributs de jointure?

Supposons que j'ai deux tables, t1 et t2 , elles ressemblent à ceci:

t1 :

CREATE TABLE "t1" ( "id" INTEGER, "value" INTEGER);
CREATE TABLE "t2" ( "id" INTEGER, "value" INTEGER);
INSERT INTO t1 VALUES (1, 1), (2, 1), (3, 2), (4, 12), (5, 13);
INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 10);

t2 :

SELECT t1.id, t1.value, t2.id
FROM t1 LEFT JOIN t2
ON t1.value = t2.value -- I don't know what to do here

J'essaie de joindre à gauche les deux tables en fonction de la différence minimale entre t1.value et t2.value , de sorte que le résultat contienne tous les enregistrements de t1 avec leur partenaire correspondant le plus proche de t2 code>, donc

t1.id, t1.value,t2.id
1,1,1
2,1,1
3,2,2
4,12,3
5,13,3

Je suppose que la requête ressemblerait à ceci:

id, value
1, 1
2, 2
3, 10

Voici les requêtes SQLite à reproduire les tableaux:

id, value
1, 1
2, 1
3, 2
4, 12
5, 13


3 commentaires

Vous devez nous dire - que signifie «partenaire correspondant le plus proche»? Comment pouvez-vous programmer cela si vous ne pouvez pas dire? Quand vous le dites clairement, cela va évidemment être presque certainement une FAQ. Avant d'envisager de publier, veuillez toujours rechercher sur Google tout message d'erreur et de nombreuses phrases claires, concises et précises de votre question / problème / objectif, avec et sans vos chaînes / noms particuliers; lire de nombreuses réponses. Si vous postez une question, utilisez un seul libellé comme titre. Voir Comment demander et les textes de la flèche de vote.


Salut philipxy, le prédicat de jointure est décrit dans la première partie de cette phrase -> "joindre à gauche les deux tables en fonction de la différence minimale entre t1.value et t2.value". Est-ce ce que vous vouliez dire avec votre question?


"Basé sur" ne dit rien et "la différence minimale entre t1.value et t2.value" n'est pas claire. Vous écrivez un tas de fragments de phrases mais vous ne les mettez pas dans une déclaration claire.


3 Réponses :


1
votes

Vous pouvez le faire comme ceci:

| id  | value | id  |
| --- | ----- | --- |
| 1   | 1     | 1   |
| 2   | 1     | 1   |
| 3   | 2     | 2   |
| 4   | 12    | 3   |
| 5   | 13    | 3   |

Vous vous inscrivez sur le minimum absolu de t1.value - t2.value .
Consultez la démo .
Résultats:

SELECT t1.id, t1.value, t2.id
FROM t1 LEFT JOIN t2
ON abs(t1.value - t2.value) = (select min(abs(t1.value - value)) from t2)


0 commentaires

1
votes

Variante qui utilise les fonctions de fenêtre ajoutées dans Sqlite 3.25 au lieu d'une sous-requête corrélée:

id          value       id2       
----------  ----------  ----------
1           1           1         
2           1           1         
3           2           2         
4           12          3         
5           13          3         

qui donne

WITH cte(id, value, id2, rnk) AS
 (SELECT t1.id, t1.value, t2.id
       , rank() OVER (PARTITION BY t1.id ORDER BY abs(t1.value - t2.value))
  FROM t1
  LEFT JOIN t2)
SELECT id, value, id2
FROM cte
WHERE rnk = 1
ORDER BY id;


0 commentaires

1
votes

Je recommanderais une sous-requête corrélée:

select t1.*,
       (select t2.value
        from t2
        where t2.id <= t1.id
        order by t2.id desc
        limit 1
       ) as t2_value
from t1;


1 commentaires

Même s'il y a trois bonnes réponses publiées jusqu'à présent, celle-ci est de loin la plus performante, donc je la marque comme acceptée. Merci à toutes les personnes impliquées!