SQL服务器:基于2个明细表的相似记录

SQL Server: similar records based on 2 detail tables

我需要在 SQL Server 2016 中找到类似的记录,如果我能根据它们的匹配程度对结果进行排序,那就太好了。 类似的匹配条件是 2 个细节 tables.

我的table结构是:

//Basic:
Id      Title
1       Title 1
2       Title 2
3       Title 3
4       Title 4
5       Title 5

//Parameters:
Id      Title
1       Param 1
2       Param 2
3       Param 3
4       Param 4
5       Param 5

//Values:
Id      Value
1       Val 1
2       Val 2
3       Val 3
4       Val 4
5       Val 5

与连接tables:

BasicId     ParameterId     ValueId
1           1               2
1           3               1
1           4               5
2           1               1
2           2               4
2           3               2
3           1               2
3           3               1
3           4               4
4           1               2
4           4               2
4           5               2
5           1               1
5           2               5
5           3               3

在我的程序中的某个时刻,我使用参数和值创建了新的基本行(在内存中)。现在我需要知道:

  1. 数据库中是否有完全匹配相同参数和值的记录。
  2. 相似记录按匹配的参数和值的数量排序。

对于第一点,我是这样做的: 如果所有参数和值匹配,则 2 行相等。 现在我用所有参数和值的 ID 计算字符串并将其添加到 Basic table.

基本变为:

Id          Title           EqualString (this comes from connection table)
1           Title 1         1:2;3:1;4:5     
2           Title 2         1:1;2:4;3:2
3           Title 3         1:2;3:1;4:4
4           Title 4         1:2;4:2;5:2
5           Title 5         1:1;2:5;3:3

效果很好,因为顺序是由 ParameterId ASC 定义的,而且我在 EqualString 列上有索引。在这一点上我应该说,我的基本 table 有大约 500 万条记录并且还在增长。

但是对于第二个问题,我不知道如何解决这种问题。

例如:

Input Title X1    1:1;2:4;3:2       100%        Title 2
                                    33%         Title 5

Input Title X2    1:1;2:4;3:1       66%         Title 2
                                    33%         Title 5

Input Title X3    1:2;3:1;5:5       66%         Title 1
                                    66%         Title 3

Input Title X4    1:2;3:1;5:3       66%         Title 3
                                    33%         Title 5

我使用 SQL Server 2016 并且可以完全控制安装数据库的计算机。
大约有 100 个参数值要检查它们是否匹配(在上面的示例中只有 3 个 - 它们用 ; 分隔)

我认为全文搜索不是答案(或者也许是),因为我需要 2 个逗号之间的精确匹配(例如 2:5)。

或者我应该采用完全不同的方法而不计算 EqualString(在插入 时很少)。

用例:

我正在构建销售动态产品的网页。这意味着,该用户在购买前对其进行配置。
例如:设置高度、宽度、颜色,选择material ... 现在我需要知道这个产品是否已经存在(其他人选择完全相同的参数(宽度、高度、颜色)和值(100、120、绿色)或者这是全新的产品。
配置的参数在参数 table 中,值在值 table.

测试数据

这是从问题中逐字复制的:

CREATE TABLE #Connection( BasicId INT, ParameterId INT, ValueId INT )
INSERT INTO #Connection
VALUES
( 1, 1, 2 ), ( 1, 3, 1 ), ( 1, 4, 5 ),
( 2, 1, 1 ), ( 2, 2, 4 ), ( 2, 3, 2 ),
( 3, 1, 2 ), ( 3, 3, 1 ), ( 3, 4, 4 ),
( 4, 1, 2 ), ( 4, 4, 2 ), ( 4, 5, 2 ),
( 5, 1, 1 ), ( 5, 2, 5 ), ( 5, 3, 3 )

这是新产品的示例数据

CREATE TABLE #NewConnection( BasicId INT, ParameterId INT, ValueId INT )
INSERT INTO #NewConnection
VALUES
( 10, 1, 2 ), ( 10, 2, 2 ), ( 10, 3, 1 ),
( 11, 1, 1 ), ( 11, 2, 4 ), ( 11, 3, 2 ),
( 12, 1, 0 ), ( 12, 2, 5 ), ( 12, 3, 3 )

查询

SELECT NC.BasicID AS NewBasicID, C.BasicID, C.ParameterId, C.ValueId,
    CONVERT( DECIMAL( 5, 0 ), COUNT( C.ParameterId ) OVER( PARTITION BY NC.BasicID, C.BasicID )) / ParamCount * 100 AS MatchStrength
FROM
        ( SELECT *, COUNT( ParameterId ) OVER( PARTITION BY BasicID ) AS ParamCount
        FROM #NewConnection ) AS NC
    INNER JOIN #Connection AS C
            ON NC.ParameterId = C.ParameterId AND C.ValueId = NC.ValueId
ORDER BY NewBasicID, MatchStrength DESC, C.BasicID, C.ParameterId

工作原理

  • #NewConnection - 包含需要根据现有 #Connection table
  • 检查的 "New Connection" 数据
  • ParamCount - 计算每个 "new" BasicID 的属性数。需要计算 MatchStrength
  • INNER JOIN - 在 ParameterIDs 和 ValueIDs
  • 上加入 "new" 与现有连接的连接
  • MatchStrength - 计算每个 NC.BasicID、C.BasicID 组的 匹配 ParameterIdValueID 组合,然后除以 ParamCount 得到匹配的百分比。

参考文献:

注意: 大型数据集的性能尚未经过测试,但您可能需要以下索引:{ parameterID, valueID }, { BasicID }

查询变体

如果您想 return 区分匹配的 BasicID 和 MatchStrength(无参数 ID),请使用以下内容:

SELECT DISTINCT NewBasicID, BasicID, MatchStrength
FROM
    ( SELECT NC.BasicID AS NewBasicID, C.BasicID, C.ParameterId, C.ValueId,
        CONVERT( DECIMAL( 5, 0 ), COUNT( C.ParameterId ) OVER( PARTITION BY NC.BasicID, C.BasicID )) / ParamCount * 100 AS MatchStrength
    FROM
            ( SELECT *, COUNT( ParameterId ) OVER( PARTITION BY BasicID ) AS ParamCount
            FROM #NewConnection ) AS NC
        INNER JOIN #Connection AS C
                ON NC.ParameterId = C.ParameterId AND C.ValueId = NC.ValueId ) AS Matches
ORDER BY NewBasicID, MatchStrength DESC, BasicID