【问题标题】:How to select from MySQL database rows containing more than 3 required words in the same column?如何从同一列中包含超过 3 个必需单词的 MySQL 数据库行中进行选择?
【发布时间】:2017-04-13 12:26:50
【问题描述】:

我有一个大型数据库(超过 200 万行),用于存储来自用户的统计信息。用户具有包含部分的唯一 ID(例如散列 MAC 地址)。 示例唯一 ID 字符串为:

“AAAAAA-BBBBBB-CCCCCC-DDDDDD-EEEEEE-FFFFFFF”

有时唯一 ID 的一部分会发生变化,例如:

“ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX”

我想使用 PHP 识别用户并选择至少 3 个(或不同值)唯一 ID 部分匹配的所有行。有什么有用的语法可以用来做这件事吗?我知道我可以选择包含至少 1 个唯一 ID 部分的所有行,然后通过“-”字符分解为一个数组并检查是否包含至少 3 个相同的单词,但我相信这不是最快的方法。

基本上,我想使用类似的东西:

WHERE `UniqueID` REGEXP 'AAAAAA|BBBBBB|CCCCCC|DDDDDD|EEEEEE|FFFFFFF';

但仅在 6 个单词中有 3 个匹配时才选择。

【问题讨论】:

  • 你的唯一ID应该分成多列,这样会简单得多。还有,火柴的位置一定要匹配吗?
  • 如果您一直拥有相同类型的数据“信用卡样式与字母相似”,您可能会对THISTHISTHIS 感兴趣
  • 感谢您的回答!不幸的是,这些列可以包含不同顺序的“唯一 id 部分”。有时唯一 ID 可以更短(例如 4 部分而不是 6 部分)等。这些部分通常是散列的硬件信息(随机长度的数字,最长 12 个字符)。
  • 'AAAAAA|BBBBBB|CCCCCC|DDDDDD|EEEEEE|FFFFFFF' 等价于like a or like b or like c or like d or like e or like f.但是无论他们的位置如何,您都想要至少三场比赛??
  • 是的@krishKM,这就是我需要的。

标签: php mysql database


【解决方案1】:

您可能想要检查性能

考虑这个查询,它使用 inStr 检查您的 id 字符串中是否有可用的字符串。我使用 substring_index 来提取零件。以防万一您有兴趣拆分或提取部分 id 字符串以创建临时表,但对于此答案,您可以忽略它。

最好用关键字1,关键字2和关键字3作为参数创建自己的存储过程,然后您可以执行搜索并返回结果。

Where 条件检查是否在您的 id 字符串中找到关键字 1、2 和 3。

select 
    'ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX' as Id,
    substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 1) as part1,
    substring_index(substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 2),'-', -1) as part2,
    substring_index(substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 3),'-', -1) as part3,
    substring_index(substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 4),'-', -1) as part4,
    substring_index(substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 5),'-', -1) as part5,
    substring_index(substring_index('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','-', 6),'-', -1) as part6
from dual
WHERE

    instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','BBBBBB') >= 1 -- keyword1
    and instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','CCCCCC') >= 1 -- keyword2
    and instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX','DDDDDD') >= 1 -- keyword3
;

编辑 如果上述查询有效,您可以添加您的逻辑。

select 
    'ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX' as Id


from dual
WHERE
    (
    -- below logic gives true when 3 or more keywords are found. change this accordingly
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik1) >0)+
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik2) >0)+
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik3) >0)+
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik4) >0)+
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik5) >0)+
        (instr('ZZZZZZ-BBBBBB-CCCCCC-DDDDDD-EEEEEE-XXXXXXX',ik6) >0)
    ) >=3

;

【讨论】:

  • 感谢您的宝贵时间。我对其进行了测试,从大约 200 万行数据库中进行选择需要 5 秒钟。但是,我不明白一件事:查询应该搜索 6 个关键字,并且只有在 3 个或更多匹配时才成功。当我添加一个额外的“and instr(UniqueID,'xxxxxxxxx') >= 1 --keyword4”时,查询不起作用。所以我想我需要使用“OR”,但只有在有 3 个匹配项时才选择...
  • 太棒了!谢谢您的帮助。我将在单独的“答案”中发布我是如何使用 PHP 做到的。
【解决方案2】:

感谢@krishKM,我找到了使用 PHP 选择唯一 ID 的最佳解决方案。

首先我创建了一个函数,它将唯一 ID 部分放入一个数组中,但在两边都保留了“分隔符”。它有助于防止错误的选择,例如当 ID 部分很短时。

function SplitUniqueIDKeepDelimeters($UniqueID, $Delimeter = "-"){
    $UniqueIDParts = array();
    $Remaining = $UniqueID;
    $pos = strpos($Remaining, $Delimeter);
    $firstPart = true;
    while ($pos !== false) {
        $Part = substr($Remaining,0,$pos + 1);
        if(!$firstPart){
            $Part = $Delimeter.$Part;
        }
        $firstPart = false;
        $UniqueIDParts[] = $Part;
        $Remaining = substr($Remaining,$pos+1);
        $pos = strpos($Remaining, $Delimeter);
    }
    if(!$firstPart){
        $Remaining = $Delimeter.$Remaining;
    }
    $UniqueIDParts[] = $Remaining;
    return $UniqueIDParts;
}

然后根据@krishKM 的回答,我创建了选择语法:

function GenerateSelectingString($UniqueIDParts, $RowName = "UniqueID", $HowManyMatches = 3){
    $First = true;
    $FinishedString = " (";
    foreach ($UniqueIDParts as $key => $value){
        if(!$First){
            $FinishedString .= "+";
        }
        $First = false;
        $FinishedString .= "(instr(`".$RowName."`,'".$value."') > 0)";

    }
    $FinishedString .= ") >=".$HowManyMatches;
    return $FinishedString;
}

测试:

$TestArray = SplitUniqueIDKeepDelimeters("21680-7886-2761736077-72316693-753974682-041548389245");
$TestSelectString = GenerateSelectingString($TestArray, "UniqueID");

echo "Unique ID parts array:<br>";
var_dump($TestArray);
echo "<br><br>Query String:<br>";
echo $TestSelectString;
echo "<br>";

$sql2 = "SELECT * FROM `Statistics`.`Statistics` WHERE ".$TestSelectString. " order by `lognumber` DESC;";
    $result2 = mysqli_query($conn, $sql2);
    if (mysqli_num_rows($result2) > 0) {
    while($row2 = mysqli_fetch_assoc($result2)) {
    echo "<br>";
    var_dump($row2);
    echo "<br>";
    }
}
else{
    echo "<br>".mysqli_errno($conn) . ": " . mysqli_error($conn) . "\n";
}

输出:

Unique ID parts array: array(6) { [0]=> string(6) "21680-" [1]=> string(6) "-7886-" [2]=> string(12) "-2761736077-" [3]=> string(10) "-72316693-" [4]=> string(11) "-753974682-" [5]=> string(13) "-041548389245" } 

Query String: ((instr(`UniqueID`,'21680-') > 0)+(instr(`UniqueID`,'-7886-') > 0)+(instr(`UniqueID`,'-2761736077-')
> 0)+(instr(`UniqueID`,'-72316693-') > 0)+(instr(`UniqueID`,'-753974682-') > 0)+(instr(`UniqueID`,'-041548389245') > 0)) >=3

array(60) {  ...

【讨论】:

    猜你喜欢
    • 2012-12-05
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多