Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL选择具有差异容忍度的不同_Mysql_Distinct - Fatal编程技术网

MySQL选择具有差异容忍度的不同

MySQL选择具有差异容忍度的不同,mysql,distinct,Mysql,Distinct,在我的数据库中,我有许多非常相似但不完全相同的条目。例如,只有两个字符可能不同,例如: 罗1:天气很好,看到了吗 罗2:天气很好,看到了吗 我想去掉这些部分重复项,只接收这两行的一个结果。不管是哪一个,我建议使用出现的第一个 我可以利用MySQL中的任何功能来高效地完成这项工作吗?我的第一个想法是提取更多数据并对字符串进行比较,如果匹配字符超过某个阈值,而不是忽略它。缺点是,我永远不知道我必须从数据库中提取多少条目,而且效率也很低,因为我必须将每一行与表中的所有其他行进行比较 更新: 更具体地说

在我的数据库中,我有许多非常相似但不完全相同的条目。例如,只有两个字符可能不同,例如:

罗1:天气很好,看到了吗

罗2:天气很好,看到了吗

我想去掉这些部分重复项,只接收这两行的一个结果。不管是哪一个,我建议使用出现的第一个

我可以利用MySQL中的任何功能来高效地完成这项工作吗?我的第一个想法是提取更多数据并对字符串进行比较,如果匹配字符超过某个阈值,而不是忽略它。缺点是,我永远不知道我必须从数据库中提取多少条目,而且效率也很低,因为我必须将每一行与表中的所有其他行进行比较

更新: 更具体地说,在用例中:方差的位置并不总是在字符串的末尾,它也可能不止两个字符会发生变化。字符串长度因每行而异。

您可以使用SOUNDEX

SOUNDEX(str)
Returns a soundex string from str. Two strings that sound almost the same should have identical soundex strings. A standard soundex string is four characters long, but the SOUNDEX() function returns an arbitrarily long string. You can use SUBSTRING() on the result to get a standard soundex string. All non-alphabetic characters in str are ignored. All international alphabetic characters outside the A-Z range are treated as vowels.

mysql> SELECT SOUNDEX('Hello');
+---------------------------------------------------------+
| SOUNDEX('Hello')                                        |
+---------------------------------------------------------+
| H400                                                    |
+---------------------------------------------------------+
1 row in set (0.00 sec)
资料来源:

例如,在Oracle PL/SQL中,字符串具有相同的SOUNDEX,并且SOUNDEX无法区分:

select soundex ('The weather is nice, see http://xyz56.com') from dual;

SOUNDEX('THEWEATHERISNICE,SEEHTTP://XYZ56.COM')
-----------------------------------------------
T362                                           
1 row selected.

select soundex ('The weather is nice, see http://xyz31.com') from dual;

SOUNDEX('THEWEATHERISNICE,SEEHTTP://XYZ31.COM')
-----------------------------------------------
T362                                           
1 row selected.

我的建议是使用,这是字符串相似性的度量。要让MySQL直接计算,您必须在存储过程中实现它,这里有一个示例:


PHP和Java也有常见的实现。

MySQL的Levenshtein距离算法:

请参阅:

Levenshtein距离 两个字符串之间的Levenshtein距离是将一个字符串转换为另一个字符串所需的最小操作数,其中一个操作可能是插入、删除或替换一个字符。Jason Rust在上发布了此MySQL算法


Levenshtein距离算法:Oracle PL/SQL实现

资料来源:

如果假设有一个名为EMPLOYEES的表,其列名为FIRST_NAME,类型为VARCHAR2,则可以很容易地找到Levenshtein Distance=1的记录,如下所示:

SELECT *
  FROM employees alfa
 WHERE EXISTS
          (SELECT 'X'
             FROM employees beta
            WHERE ld (beta.first_name, alfa.first_name) = 1);
通过此查询,您可以在结果集的每一行中显示Levenshtein距离为1的第一个\u名称的列表:

SELECT a.first_name, b.first_name
  FROM    employees a
       INNER JOIN
          employees b
       ON ld (b.first_name, a.first_name) = 1;
例如:

SELECT DISTINCT a.first_name, b.first_name
  FROM    employees a
       INNER JOIN
          employees b
       ON ld (b.first_name, a.first_name) <= 2
          AND ld (b.first_name, a.first_name) > 0;

FIRST_NAME;FIRST_NAME_1
Jean;John
Nancy;Vance
Alana;Allan
Alana;Clara
Ellen;Eleni
John;Jean
Daniel;Danielle
Danielle;Daniel
Shelley;Shelli
Sundita;Nandita
Lisa;Luis
Stephen;Steven
Nanette;Janette
Diana;Alana
TJ;Ki
Luis;Lisa
Sarath;Sarah
Louise;Luis
Ki;TJ
Allan;Ellen
Luis;Louise
Den;Lex
Clara;Alana
Matthew;Mattea
Shelli;Shelley
Sarah;Sarath
Girard;Gerald
Vance;Nancy
Mattea;Martha
Allan;Alana
Nandita;Sundita
Ellen;Allan
Jean;Den
Eleni;Ellen
Gerald;Girard
Lex;Den
Janette;Nanette
Steven;Stephen
Mattea;Matthew
Den;Jean
Martha;Mattea
Alana;Diana

Soundex可以在大多数数字变化的情况下工作,但并不总是有效,例如,对于以下用例:第1行:在我的iPhone上的原始Gangstaz上刚刚达到55级!点击链接加入我的帮派iphone ipod OG第2排:在我的iphone上刚刚达到全球战争在线35级!单击链接加入我的团队iphone ipod。对于每一行,字符串的长度和变化的位置是不同的,看起来很有希望,但我不知道如何在查询大量数据时应用这一点,而不仅仅是比较两个字符串?非常有趣的解决方案,Paul,恭维!我从来没有听说过Levenshtein距离,我发现它是一个非常有用的概念。如果你已经有很多可能是半重复的数据,那么没有办法有效地做到这一点。钝的方法将比较效率为二次的任何两个字符串。我认为最好的方法是删除重复数据或“修复”当前数据(修复效率可能很低),然后计算插入点上可能存在的半重复数据。更好的方法是不完全使用字符串差异,向模型中添加更多结构,以便可以依赖记录的存在,并使用您的db索引。在Oracle PL/SQL中,您可以轻松找到满足Levenshtein distance=1条件的记录,例如,使用SELECT*FROM employees alfa(存在)从employees beta中选择“X”,其中ld beta.first_name,alfa.first_name=1;谢谢我实现了这个过程,并运行了一个查询,计算了我所选结果的Levenshtein距离(20行到一个硬编码字符串)。这已经使运行时慢了大约四倍,所以不幸的是,我认为这不适合限制查询,特别是因为我有>20000行。
CREATE OR REPLACE FUNCTION ld -- Levenshtein distance
  (p_source_string   IN VARCHAR2,
   p_target_string   IN VARCHAR2)
  RETURN                NUMBER
  DETERMINISTIC
AS
  v_length_of_source    NUMBER := NVL (LENGTH (p_source_string), 0);
  v_length_of_target    NUMBER := NVL (LENGTH (p_target_string), 0);
  TYPE mytabtype IS     TABLE OF NUMBER INDEX BY BINARY_INTEGER;
  column_to_left        mytabtype;
  current_column        mytabtype;
  v_cost                NUMBER := 0;
BEGIN
  IF v_length_of_source = 0 THEN
    RETURN v_length_of_target;
  ELSIF v_length_of_target = 0 THEN
    RETURN v_length_of_source;
  ELSE
    FOR j IN 0 .. v_length_of_target LOOP
      column_to_left(j) := j;
    END LOOP;
    FOR i IN 1.. v_length_of_source LOOP
      current_column(0) := i;
      FOR j IN 1 .. v_length_of_target LOOP
        IF SUBSTR (p_source_string, i, 1) =
           SUBSTR (p_target_string, j, 1)
        THEN v_cost := 0;
        ELSE v_cost := 1;
        END IF;
        current_column(j) := LEAST (current_column(j-1) + 1,
                                    column_to_left(j) + 1,
                                    column_to_left(j-1) + v_cost);
      END LOOP;
      FOR j IN 0 .. v_length_of_target  LOOP
        column_to_left(j) := current_column(j);
      END LOOP;
    END LOOP;
  END IF;
  RETURN current_column(v_length_of_target);
END ld;
SELECT *
  FROM employees alfa
 WHERE EXISTS
          (SELECT 'X'
             FROM employees beta
            WHERE ld (beta.first_name, alfa.first_name) = 1);
SELECT a.first_name, b.first_name
  FROM    employees a
       INNER JOIN
          employees b
       ON ld (b.first_name, a.first_name) = 1;
SELECT DISTINCT a.first_name, b.first_name
  FROM    employees a
       INNER JOIN
          employees b
       ON ld (b.first_name, a.first_name) <= 2
          AND ld (b.first_name, a.first_name) > 0;

FIRST_NAME;FIRST_NAME_1
Jean;John
Nancy;Vance
Alana;Allan
Alana;Clara
Ellen;Eleni
John;Jean
Daniel;Danielle
Danielle;Daniel
Shelley;Shelli
Sundita;Nandita
Lisa;Luis
Stephen;Steven
Nanette;Janette
Diana;Alana
TJ;Ki
Luis;Lisa
Sarath;Sarah
Louise;Luis
Ki;TJ
Allan;Ellen
Luis;Louise
Den;Lex
Clara;Alana
Matthew;Mattea
Shelli;Shelley
Sarah;Sarath
Girard;Gerald
Vance;Nancy
Mattea;Martha
Allan;Alana
Nandita;Sundita
Ellen;Allan
Jean;Den
Eleni;Ellen
Gerald;Girard
Lex;Den
Janette;Nanette
Steven;Stephen
Mattea;Matthew
Den;Jean
Martha;Mattea
Alana;Diana