我的MYSQL数据库中有一个地址表,其结构如下:
我希望根据地址/地址段显示所有记录并突出显示可能的重复项。
在这种情况下,重复项如下:
有没有一种方法可以部分匹配MYSQL或PHP中的字符串,以实现上述结果?
仅供参考:我已经完成了SPHINX PHP,SQL FULLTEXT SEARCHES等工作。
我已经苦苦挣扎了2个多星期,但找不到最佳解决方案。
欢迎任何想法,建议和解决方案。
答案 0 :(得分:1)
由于laravel
最初是被标记的,后来被删除了,所以我认为该策略仍然可以提供帮助。
这是给定的列表:
$lists = [
[
'id' => 1,
'text' => '2693 Edgewood Road Exit',
],
[
'id' => 2,
'text' => '4408 Cost 4657 Avenue',
],
[
'id' => 3,
'text' => '2693 Mapleview Road',
],
[
'id' => 4,
'text' => '4657 Cost Edgewood Avenue',
],
[
'id' => 5,
'text' => '4408 Mapleview Drive Road',
]
];
目标是从每个文本中查找重复/重复的文本。
由于发现一个单词的重复不是一个真实的情况,所以我想到了以两个单词以及所有可能的组合来查找重复的单词。
$combinations = [];
foreach ($lists as $list) {
$insideCombo = [];
$insideText = explode(' ', $list['text']);
$length = count($insideText);
for ($i = 0; $i < $length; $i++) {
for ($j = $i + 1; $j < $length; $j++) {
if (isset($insideText[$j])) {
$insideCombo[] = $insideText[$i] . ' ' . $insideText[$j];
}
}
}
$combinations[$list['id']] = $insideCombo;
}
这会回来的
// for '2693 Edgewood Road Exit'
1 => array:6 [
0 => "2693 Edgewood"
1 => "2693 Road"
2 => "2693 Exit"
3 => "Edgewood Road"
4 => "Edgewood Exit"
5 => "Road Exit"
]
现在,我们再次循环比较可能的重复。在这里,我们利用Laravel的Str::containsAll()
$copyCat = [];
foreach ($lists as $list) {
foreach ($combinations as $comboKey => $combination) {
/* no need to compare the text with itself &&
* to avoid duplication of '4 to 2' if '2 to 4' is already mentioned
*/
if ($list['id'] != $comboKey && $list['id'] < $comboKey) {
foreach ($combination as $row) {
if (Str::containsAll($list['text'], explode(' ', $row))) {
$copyCat[] = $list['id'] . ' matches with ' . $comboKey . ' with "' . $row . '"';
}
}
}
}
}
最终答复,$copyCat
array:5 [
0 => "1 matches with 3 with [2693 Road]"
1 => "2 matches with 4 with [4657 Cost]"
2 => "2 matches with 4 with [4657 Avenue]"
3 => "2 matches with 4 with [Cost Avenue]"
4 => "3 matches with 5 with [Mapleview Road]"
]
将我保留在下面的评论中。干杯!
答案 1 :(得分:1)
mytable_to_update
。SELECT SUBSTRING_INDEX(Name,' ',1),COUNT(*)
FROM mytable_to_update
GROUP BY SUBSTRING_INDEX(Name,' ',1) HAVING COUNT(*) = 1;
SUBSTRING_INDEX将捕获空格('')之前的第一个字符串。在此示例中,Sam Mcarthy
仅会变成Sam
。然后使用该数据分组并计算出现的名称数量。 HAVING COUNT(*) = 1
仅显示一次出现的任何名称。但是,如果有Joe
和Joe John
之类的名字,但实际上这两个人实际上是具有不同地址的另一个人,则这可能不会返回任何内容(因为第一个查询仅按名字进行分组)。因此,我们需要在组合中添加address
比较。
Address
列中添加相同的功能:SELECT SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1), /*we take the first string in the address*/
COUNT(*)
FROM mytable_to_update
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1) /*then add group by for the address*/
HAVING COUNT(*) = 1;
同样,我们仅从地址中获取第一个字符串。假设有两个看起来像这样的数据Joe, 12 Street..
和Joe John, 12 St. ..
,将发生的是上面的查询(根据SUBSTRING_INDEX
函数)仅出现第一个字符串; Joe, 12
,将返回计数值为2。这意味着数据(Joe, 12 Street..
和Joe John, 12 St. ..
)都被视为重复项,并且不会显示在查询结果中。
ID
表中的所有非重复项mytable_to_update
:INSERT INTO mytable_to_update
SELECT * FROM mytable WHERE ID IN
(SELECT GROUP_CONCAT(ID) /*replace everything else in the select with just `ID`*/
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) = 1) ;
注意:我正在使用GROUP_CONCAT(ID),因为sql_mode = only_full_group_by不兼容-如果正在设置它。当然结果可能会有所不同(例如'1,2'或'1 ,,,,'),但是由于我们只看任何count = 1,因此它不会有问题,因为它只会返回1值。我已经用ANY_VALUE测试过,它也会返回类似的结果。
现在,您在mytable_to_update
表中拥有所有非重复项。下一步是搜索重复项,然后插入您只需要的重复项。这只是您可能想要的建议/假设,由于我们正在比较的数据值的性质,它并不是100%准确。
SELECT GROUP_CONCAT(ID), /*add GROUP_CONCAT to list all the duplicates group by the first name & address string.*/
Name,
Address,
COUNT(*)
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1; /*Change '= 1' to '> 1' to get any records with more than 1 count.*/
使用GROUP_CONCAT生成以逗号分隔的ID
列表,该列表可能重复。
GROUP_CONCAT
添加到所有列有相同ORDER BY
的列上,以便每个列都按相同的顺序排序。SELECT GROUP_CONCAT(ID ORDER BY ID), /*add ORDER BY*/
GROUP_CONCAT(Name ORDER BY ID),
GROUP_CONCAT(Address ORDER BY ID),
COUNT(*)
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1;
通过此操作,您可以遍历返回的所有重复值,并进行比较。这样,您可以通过添加WHERE ID NOT IN(1,3 ...)
等来决定省略不想显示在列表中的任何ID。
ID
后,您可以执行以下操作:INSERT INTO mytable_to_update
SELECT * FROM mytable WHERE ID IN
(SELECT SUBSTRING_INDEX(GROUP_CONCAT(ID ORDER BY ID),',',1)
/*assuming that you only want the first ID in the set, do SUBSTRING_INDEX to separate the first ID*/
FROM mytable
GROUP BY SUBSTRING_INDEX(Name,' ',1),
SUBSTRING_INDEX(Address,' ',1)
HAVING COUNT(*) > 1);
现在,您将有一个表(mytable_to_update
),该表可能包含所有非重复项。如果mytable_to_update
中的某些数据不是您想要的,则可以将其删除,或者如果您认为某些数据不是重复的,则可以将其插入。此后几乎是一个手动过程。好吧,即使有查询,也只有您自己才能确定过程/数据是否正确。
这是一个小提琴:https://www.db-fiddle.com/f/6Dfrn78mqZbGTwZs3U9Vhi/0