通过函数比较数据

时间:2010-04-13 19:41:02

标签: sql-server tsql

我在不同的表中有两组数据(位置),我需要比较它们是否匹配。我有一个UDF,它根据每个表中的5个值执行计算。

如何使用此udf执行带连接的选择?

我的udf基本上是由......定义的。

ALTER FUNCTION [dbo].[MatchRanking]
(
        @Latitude       FLOAT
    ,   @Longitude      FLOAT
    ,   @Postcode       VARCHAR(16)
    ,   @CompanyName    VARCHAR(256)
    ,   @TelephoneNumber VARCHAR(32)
    ,   @Latitude2      FLOAT
    ,   @Longitude2     FLOAT
    ,   @Postcode2      VARCHAR(16)
    ,   @CompanyName2   VARCHAR(256)
    ,   @TelephoneNumber2 VARCHAR(32)

)
RETURNS INT
WITH EXECUTE AS CALLER
AS
BEGIN

    DECLARE @RetVal INT
    DECLARE @PostcodeVal INT
    SET @RetVal = 0
    SET @PostcodeVal = 0

    SET @RetVal = @RetVal + dbo.FuzzyLogicStringMatch(@CompanyName, @CompanyName2)

    IF @RetVal = 1 AND dbo.TelephoneNoStringMatch(@TelephoneNumber, @TelephoneNumber2) = 1
        RETURN 5
    ELSE
        IF @RetVal = 1 AND dbo.FuzzyLogicStringMatch(@Postcode, @Postcode2) = 1
            RETURN 5
        ELSE
            IF @RetVal = 1 AND ROUND(@Latitude,4) = ROUND(@Latitude2,4) AND ROUND(@Longitude,4) = ROUND(@Longitude2,4)
                RETURN 5
            ELSE
                IF (@RetVal = 1 AND ROUND(@Latitude,4) = ROUND(@Latitude2,4)) OR (@RetVal = 1 AND ROUND(@Longitude,4) = ROUND(@Longitude2,4))
                    SET @RetVal = 2
                ELSE
                BEGIN                   
                    IF ROUND(@Latitude,4) = ROUND(@Latitude2,4)
                        SET @RetVal = @RetVal + 1
                    IF ROUND(@Longitude,4) = ROUND(@Longitude2,4)
                        SET @RetVal = @RetVal + 1
                    SET @RetVal = @RetVal + dbo.TelephoneNoStringMatch(@TelephoneNumber, @TelephoneNumber2)
                    SET @RetVal = @RetVal + dbo.FuzzyLogicStringMatch(@Postcode, @Postcode2)
                END

    RETURN @RetVal
END

这是我之前尝试修复的代码:

        SELECT li.LImportId, l.LocationId, dbo.MatchRanking(li.Latitude, li.Longitude, li.[Name], li.Postcode, li.TelephoneNumber,
                                l.Latitude, l.Longitude, l.CompanyName, l.Postcode, l.TelephoneNumber 
                    ) AS [MatchRanking]
          FROM @LocImport li
          LEFT JOIN [Location] l
            ON lI.[Latitude] = l.[Latitude]
            OR lI.[Longitude] = l.[Longitude]
            OR lI.[Postcode] = l.[Postcode]
            OR lI.[Name] = l.[CompanyName]
            OR lI.[TelephoneNumber] = l.[TelephoneNumber]

4 个答案:

答案 0 :(得分:0)

你原来的JOIN出了什么问题?这应该比这个功能快得多。

这应该这样做,但我认为它会非常缓慢:

SELECT
...
FROM Table1             t1
    CROSS JOIN Table2   t2
WHERE dbo.MatchRanking(t1.Latitude ,..,..,t2.Latitude ,..)=1 --"1" or whatever return value is a match

答案 1 :(得分:0)

就个人而言,我会在几次通过中进行这种模糊数据匹配。

- 创建一个外部参照表,其中包含匹配记录的键 - 完全匹配所有匹配并在外部参照表中插入键

- “模糊化”您的条件并再次搜索,但仅限于外部参照中尚未匹配的记录。

- 通过扩展和/或模糊化您的标准来重复并重复,直到您获得的匹配为垃圾。

答案 2 :(得分:0)

首先必须交叉连接两个表(m和n产生m x n比较)并比较以找到匹配 - 实际上没有其他简单方法。

然而,通过对数据及其解释和目标的元理解,如果你能以某种方式过滤你的集合以相当容易地从交叉连接中消除项目,那将有所帮助 - 特别是如果有任何必须是精确的匹配,或以任何方式对数据进行分区,以便永远不会比较不同分区中的项目(即比较美国和欧洲的位置总是匹配等级0)

我想说,如果它们相差一定数量,你可以使用Lat和Long完全消除,但看起来它们用于提高匹配排名,而不是消极排除匹配排名的项目。

重复调用的标量函数(你的FuzzyMatches)(比如数百万行交叉连接)非常昂贵。

在我看来,你可以在你的交叉连接中提取第一个匹配和内部else(如果可能的话,也可以内联,而不是UDF),以便查询优化器结合使用它们可以稍微优化它们。十字连接而不是一个名为mxn次的黑盒子。

另一种可能性是仅预先提取不同的电话号码对,邮政编码对等。

SELECT Postcode1, Postcode2, dbo.FuzzyLogicStringMatch(Postcode1, Postcode2) AS MatchRank
FROM (
    SELECT DISTINCT Postcode AS Postcode1
    FROM Table1
) AS Postcodes1
CROSS JOIN
(
    SELECT DISTINCT Postcode AS Postcode2
    FROM Table2
) AS Postcodes2

如果你的函数是对称的,你可以通过一些额外的工作来进一步减少调用UDF的空间(如果表是自连接,则更容易,你只需使用右上三角)。

现在,您可以调用标量UDF的最小比较集。将此结果放入索引在两列上的表中。

您可以对所有UDF参数集执行类似操作。如果函数定义没有改变,您只需要随着时间的推移向表中添加新的组合,将昂贵的标量函数调用转换为对相对较慢的增长数据进行表查找。如果查找表没有条目,您甚至可以使用CASE语句回退到内联UDF调用 - 这样您就可以决定是否保持查找表的全面性。

答案 3 :(得分:0)

我们做的一件事是设置一个特殊的表来存储交叉连接的结果,因此它们只需要被计算一次。然后有一个每晚运行的工作来获取任何新记录并将其填充到所有旧记录中。在所有纬度/长度不会改变之后(夜间作业可以找到和修复的偶然类型除外)并且每次运行查询以查找计算时的距离时进行此计算是没有意义的。对于大多数人而言,alwys是相同的。一旦这些数据在表格中,您就可以非常快速地进行查询。第一次填充表可能需要一段时间。