使用Scoring在SQL中查找最佳匹配

时间:2015-04-02 14:01:25

标签: sql sql-server

假设我有一个DATA表,如:

ID | Col1 | Col2 | Col3
 1    a      b      23
 2    a      c      14
 3    f      g      11

假设我有一个POSSIBLE_MATCHES表,如:

MatchID  | Col1 | Col2 | Col3
101         a      a      11
102         a      b      11
103         a      b      14
104         a      c      23
105         f      a      1

假设我有一个WEIGHTS表(如果你想为了这个讨论而简单,假设所有权重都是1 - 我可以在以后即兴发挥我的解决方案来合并权重):

Col | Weight
Col1    1
Col2    1.5
Col3    2

因此,对于每个可能的匹配,我们将在每个匹配列上计算 SCORE

    Score = Col1 Weight * (CASE WHEN DATA.COL1 = POSSIBLE_MATCHES.Col1 THEN 1 ELSE 0) + 
            Col2 Weight * (CASE WHEN DATA.COL2 = POSSIBLE_MATCHES.Col2 THEN 1 ELSE 0) +
            Col3 Weight * (CASE WHEN DATA.COL3 = POSSIBLE_MATCHES.Col3 THEN 1 ELSE 0)

例如第一行的 BEST MATCH :Col1 = a,Col2 = b,Col3 = 23:

MatchID  | Col1 | Col2 | Col3 | Score
101         a      a      11     1*1 + 1.5*0 + 2*0 = 1
102         a      b      11     1*1 + 1.5*1 + 2*0 = 2.5
103         a      b      14     1*1 + 1.5*1 + 2*0 = 2.5
104         a      c      23     1*1 + 1.5*0 + 2*1 = 3
105         f      a      1      1*0 + 1.5*0 + 2*0 = 0

所以在这种情况下,ID:1的最佳匹配是MatchID:104 。如果分数相同,则采用最低的MatchID。

如果你想玩这个,这里有一个sql小提琴: http://sqlfiddle.com/#!6/9df45/1

对于DATA中的每个ID,如何在可能的匹配中找到最佳匹配?

2 个答案:

答案 0 :(得分:2)

在此解决方案中,我们进行完全联接以获得所有可能性并评估所有可能性的得分。然后,我们使用ROW_NUMBER为它们分配从最好到最低的数字。最后,我们排除所有那些不是最好的那些“WHERE Rank = 1”

SELECT * 
FROM 
(SELECT data.ID,
        possible_matches.MatchID,
        Score =  (CASE WHEN data.Col1 = possible_matches.Col1 THEN 1 ELSE 0 END) * 1 +
                (CASE WHEN data.Col2 = possible_matches.Col2 THEN 1 ELSE 0 END) * 1.5 +
                (CASE WHEN data.Col3 = possible_matches.Col3 THEN 1 ELSE 0 END) * 2,
        [Rank] = ROW_NUMBER() OVER(PARTITION BY data.ID ORDER BY (CASE WHEN data.Col1 = possible_matches.Col1 THEN 1 ELSE 0 END) * 1 +
                                                            (CASE WHEN data.Col2 = possible_matches.Col2 THEN 1 ELSE 0 END) * 1.5 +
                                                            (CASE WHEN data.Col3 = possible_matches.Col3 THEN 1 ELSE 0 END) * 2 DESC)
from data, possible_matches) AS AllScore
WHERE AllScore.[Rank] = 1

答案 1 :(得分:1)

试试这个:

DECLARE @d TABLE(ID INT, Col1 CHAR(1), Col2 CHAR(1), Col3 INT)
DECLARE @m TABLE(ID INT, Col1 CHAR(1), Col2 CHAR(1), Col3 INT)


INSERT INTO @d VALUES
(1, 'a', 'b', 23),
(2, 'a', 'c', 14),
(3, 'f', 'g', 11)

INSERT INTO @m VALUES
(101, 'a', 'a', 11),
(102, 'a', 'b', 11),
(103, 'a', 'b', 14),
(104, 'a', 'c', 23),
(105, 'f', 'a', 1)


SELECT DataID, MatchID FROM 
(
    SELECT d.ID AS DataID, 
           m.ID AS MatchID, 
               ROW_NUMBER() OVER(PARTITION BY d.ID ORDER BY 
                CASE WHEN d.Col1 = m.Col1 THEN 1 ELSE 0 END * 1 +
                CASE WHEN d.Col2 = m.Col2 THEN 1 ELSE 0 END * 1.5 +
                CASE WHEN d.Col3 = m.Col3 THEN 1 ELSE 0 END * 2 DESC) AS rn

    FROM @d d
    CROSS JOIN @m m
) t WHERE rn = 1

输出:

DataID  MatchID
1       104
2       103
3       102