1

我需要在用户将实体保存到数据库之前生成可能重复的列表并警告他们可能的重复。

有 7 个标准我们应该检查重复项,如果至少 3 个匹配,我们应该将其标记给用户。条件将在 ID 上全部匹配,因此不需要模糊字符串匹配,但我的问题来自这样一个事实,即至少有 3 个项目可以匹配来自7 种可能的列表。

我不想执行 99 个单独的数据库查询来查找我的搜索结果,也不想从数据库中取回全部内容并在客户端进行过滤。目前我们可能只谈论几万条记录,但随着系统的成熟,这将增长到数百万条。

有没有人想到一个很好的有效方法来做到这一点?我正在考虑一个简单的 OR 查询来从数据库中获取至少一个字段匹配的记录,然后在客户端上进行一些处理以对其进行更多过滤,但是其中一些字段的基数非常低,实际上不会减少数量巨大。

谢谢乔恩

4

5 回答 5

3

ORCASE求和会起作用,但效率很低,因为它们不使用索引。

您需要使UNION索引可用。

如果用户将name、和输入到数据库中phone,并且您想要检查至少与这些字段中的一个匹配的所有记录,则发出:emailaddress3

SELECT  i.*
FROM    (
        SELECT  id, COUNT(*)
        FROM    (
                SELECT  id
                FROM    t_info t
                WHERE   name  = 'Eve Chianese'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   phone = '+15558000042'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   email = '42@example.com'
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   address = '42 North Lane'
                ) q
        GROUP BY
                id
        HAVING  COUNT(*) >= 3
        ) dq
JOIN    t_info i
ON      i.id = dq.id

这将在这些字段上使用索引,并且查询会很快。

有关详细信息,请参阅我的博客中的这篇文章:

另请参阅本文所基于的这个问题。

如果您想DISTINCT在现有数据中包含值列表,只需将此查询包装到子查询中:

SELECT  i.*
FROM    t_info i1
WHERE   EXISTS
        (
        SELECT  1
        FROM    (
                SELECT  id
                FROM    t_info t
                WHERE   name  = i1.name
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   phone = i1.phone
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   email = i1.email
                UNION ALL
                SELECT  id
                FROM    t_info t
                WHERE   address = i1.address
                ) q
        GROUP BY
                id
        HAVING  COUNT(*) >= 3
        )

请注意,这DISTINCT不是可传递的:如果A匹配BB匹配C,这并不意味着A匹配C

于 2009-05-05T16:14:55.727 回答
2

您可能需要以下内容:

SELECT id
FROM 
    (select id, CASE fld1 WHEN input1 THEN 1 ELSE 0 "rule1",
        CASE fld2 when input2 THEN 1 ELSE 0 "rule2",
        ...,
        CASE fld7 when input7 THEN 1 ELSE 0 "rule2",
    FROM table)
WHERE rule1+rule2+rule3+...+rule4 >= 3

这未经测试,但它显示了解决此问题的方法。

于 2009-05-05T16:23:05.987 回答
0

你用的是什么星展银行?一些支持通过使用服务器端代码来使用此类约束。

于 2009-05-05T16:15:49.220 回答
0

您是否考虑过使用带有游标的存储过程?然后,您可以执行 OR 查询,然后逐个遍历记录以查找匹配项。使用存储过程将允许您在服务器上进行所有检查。

但是,我认为具有数百万条记录的表扫描总是会很慢。我认为您应该找出最有可能匹配的 7 个字段中的哪一个,确保这些字段已编入索引。

于 2009-05-05T16:17:59.963 回答
0

我假设您的系统正在尝试匹配某个帖子或类似内容的标签 ID。这是一个多对多的关系,你应该有三个表来处理它。一个用于帖子,一个用于标签,一个用于帖子和标签的关系。

如果我的假设是正确的,那么处理这个问题的最佳方法是:

SELECT postid, count(tagid) as common_tag_count
FROM posts_to_tags
WHERE tagid IN (tag1, tag2, tag3, ...)
GROUP BY postid
HAVING count(tagid) > 3;
于 2009-05-05T16:19:32.797 回答