2010-05-11 3 views
1

J'ai deux tables qui sont mises à jour à presque exactement en même temps - j'ai besoin de rejoindre la colonne datetime.SQL - Comment rejoindre des colonnes similaires (non exactes)

J'ai essayé ceci:

SELECT * 
FROM A, B 
WHERE ABS(DATEDIFF(second, A.Date_Time, B.Date_Time)) = (
    SELECT MIN(ABS(DATEDIFF(second, A.Date_Time, B2.Date_Time))) 
    FROM B AS B2 
) 

Mais il me dit:

colonnes multiples sont spécifiées dans une expression agrégée contenant une référence externe. Si une expression en cours d'agrégation contient une référence externe, cette référence externe doit être la seule colonne référencée dans l'expression.

Comment puis-je joindre ces tables?

Répondre

4

Que diriez-vous quelque chose comme (en supposant SQL 2005+):

With RankedItems As 
    (
    Select A.DateTime As ADateTime, B.DateTime As BDateTime 
     , ROW_NUMBER() OVER (PARTITION BY A.DateTime ORDER BY ABS(DateDiff(s, A.DateTime, B.DateTime))) As ItemRank 
    From A 
     Cross Join B 
    ) 
Select 
From RankedItems 
Where ItemRank = 1 

Dans ma solution, j'utilise une expression table commune ou CTE pour faire court. Dans le CTE, j'utilise une fonction de classement (ROW_NUMBER) qui calcule pour chaque ligne de l'expression CTE. La fonction ROW_NUMBER renverra un entier séquentiel pour chaque valeur DateTime dans le tableau A via la clause PARTITION BY A.DateTime ordonnée par la valeur absolue de la valeur "proximité" A.DateTime à la valeur B.DateTime. Ainsi, je classe la "proximité" en utilisant Abs(DateDiff(s,A.DateTime, B.DateTime) et en choisissant le rang le plus élevé (rang = 1, alias "valeur la plus proche") pour chaque valeur A.DateTime. La fonction ROW_NUMBER() renverra une liste unique de nombres pour chaque valeur A.DateTime.

+0

Pourriez-vous peut-être expliquer comment ce code fonctionne? Je n'ai jamais vu beaucoup de ces constructions auparavant. –

+0

@BlueRaja - J'ai développé ma réponse pour fournir plus de détails. – Thomas

+0

J'ai fini par remplacer «MIN» par «TOP 1 ... ORDER BY Date_Time» dans ma requête, mais cette réponse m'a appris quelque chose de nouveau et m'a aidé avec un problème connexe (trouver toutes les lignes dans lesquelles une colonne particulière a changé avec par rapport à la rangée précédente, si elle est ordonnée par date-heure). Je vous remercie! –

2

Il est peut-être préférable de créer d'abord une vue contenant une colonne contenant votre datiff calculé, puis de créer une requête à partir de celle-ci.

3

Est-ce ce que vous voulez? Il vérifiera pendant 1 seconde différence

select * from 
A, b --use a join next time 
where A.Date_Time 
between DATEADD(s,-1,B.Date_Time) and DATEADD(s,1,B.Date_Time) 
+0

Je veux rejoindre chaque ligne de A avec la ligne de B qui a la valeur Date_Time la plus proche. Il ne sera pas nécessairement toujours dans 1 seconde –