SQL Server:基于2个详细信息表的类似记录

时间:2017-08-21 14:43:03

标签: sql-server full-text-search sql-server-2016

我需要在SQL Server 2016中找到类似的记录,如果我能按照它们的匹配顺序排序结果会很棒。 类似的匹配标准是2个详细信息表。

我的表结构是:

//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

连接表:

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

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

  1. 数据库中是否有与完全相同的参数和值匹配的记录。
  2. 按照多少参数和值匹配排序的类似记录。
  3. 首先,我这样做: 如果所有参数和值都匹配,则 2行相等。 现在我用所有参数和值的ID计算字符串,并将其添加到Basic表。

    基本变为:

    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
    

    这很好用,因为orderId是由ParameterId ASC定义的,而且我在EqualString列上有索引。在这一点上,我应该说,我的基本表有大约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(很少插入女巫)。

    使用案例

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

1 个答案:

答案 0 :(得分:1)

测试数据

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

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表检查的“新连接”数据
  • ParamCount - 计算每个“新”BasicID的属性数。需要计算MatchStrength
  • INNER JOIN - 在ParameterIDs和ValueIDs上加入与现有连接的“新”连接
  • MatchStrength - 为每个NC.BasicID,C.BasicID组计算匹配的 ParameterIdValueID组合,然后除以ParamCount获得匹配的百分比。

参考文献:

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

查询变体

如果要返回不同的匹配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