根据my previous question,软件招聘人员可以输入布尔文本字符串,例如, C++ AND ((UML OR Python) OR (not Perl))
,我将其翻译为{{ 1}}。
[更新]我突出显示了 (例如 ),因为某些答案似乎认为我只对此查询感兴趣。这只是一个例子。我寻求用PHP编码的通用解决方案。也许是正则表达式?只需一些代码即可找到查询的每个子项,以便我可以分别查询子项。 [/更新]
我想SELECT * FROM candidates WHERE skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl))
命中数,但是我也很想知道查询的每个“子句”(如果是正确的术语)对结果的贡献。 / p>
例如可能有200名使用C ++的候选人,但50名不合适,因为他们既没有UML也没有Python经验。
因此,使用PHP(和rexex?)或MySql,如何将其分解以查看搜索词的哪些部分对结果有贡献?
即,将COUNT(*)
分解为skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl))
和`COUNT(*)WHERE(技能= UML或skill = Python)等
我不知道MySql是否为此使用了某种COUNT(*) WHERE skill=C++
,但怀疑没有,所以我将不得不像描述的那样EXPLAIN
分解每个SELECT
-分别条款。
我希望我已经清楚地解释了这一点;如果没有,请要求澄清。我根本不知道从哪里开始
答案 0 :(得分:1)
我们需要一种分割条件的方法。但是,我们不能将AND和OR划分为相等,因为 AND的优先级高于OR 。
因此在这样的示例中:
Cond1 AND Cond2 OR Cond3
我们无法除以AND|OR
,因为我们整体上会缺少Cond1 AND Cond2
。
因此,第一件事是在需要的地方添加额外的括号(使用正则表达式),以便以下算法可以正确分割条件。在上一个示例中,它将为(Cond1 AND Cond2) OR Cond3
。
一旦设置,我们将使用正则表达式来获取当前Level的条件。我们需要使用递归正则表达式来检测开/关括号。
每个条件都存储在一个数组中,然后发送以进行处理(递归)。这是因为某些条件可能很复杂并且具有嵌套条件。
所有这些条件和子条件都存储在数组中。
一旦拥有所有条件(和子条件),就有两种安装SQL的选择。
第一个选项是没有WHERE子句的单个查询,每个条件一个SUM。如果表上没有那么多行,那可能是最好的方法
第二个选项是在所有条件下运行多个SELECT count(*)
查询。
我在这里留下了php代码。我还添加了一个选项,用于在拆分条件时自定义最大嵌套级别数。
您有一个关于 Ideone ,here的演示。
<?php
$conditions = 'C++ AND ((UML OR Python) OR (not Perl))';
// Other tests...
//$conditions = "C++ AND Python OR Perl";
//$conditions = "C++ AND Python OR Perl OR (Perl AND (Ruby AND Docker AND (Lisp OR (C++ AND Ada) AND Java)))";
///////// CONFIGURATION /////////
$maxNest = 0; // Set to 0 for unlimited nest levels
/////////////////////////////////
print "Original Input:\n";
print $conditions . "\n\n";
// Add implicit parenthesis...
// For example: `A AND B OR C` should be: `(A AND B) OR C`
$addParenthesis = '/(?|(((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?2)\s*+)*+[)])(?:\s*+\bAND\b\s*+((?2)))++)(?=\s*+\bOR\b\s*+)|\s*+\bOR\b\s*+\K((?1)))/im';
while (preg_match($addParenthesis, $conditions)) {
$conditions = preg_replace($addParenthesis, '(\1)', $conditions);
}
print "Input after adding implicit parenthesis (if needed):\n";
print $conditions . "\n\n";
// Optional cleanup: Remove useless NOT () parenthesis
$conditions = preg_replace('/[(]\s*((?:NOT\s*)?+(\S+))\s*[)]/i', '\1', $conditions);
// Optional cleanup: Remove useless NOT NOT...
$conditions = preg_replace('/\bNOT\s+NOT\b/i', '', $conditions);
$list_conditions = [$conditions];
function split_conditions($input, $level = 0) {
global $list_conditions, $maxNest;
if ($maxNest > 0 && $level >= $maxNest) { return; }
// If it is a logic operator, skip
if ( preg_match('/^\s*(?:AND|OR)\s*$/i', $input) ) {
return;
}
// Add condition to the list:
array_push($list_conditions, $input);
// Don't go on if this is a single filter
if ( preg_match('/^\s*(?:NOT\s+)?+[^)(\s]+\s*$/i', $input) ) {
return;
}
// Remove parenthesis (if exists) before evaluating sub expressions
// Do this only for level > 0. Level 0 is not guaranteed to have
// sorrounding parenthesis, so It may remove wanted parenthesis
// such in this expression: `(Cond1 AND Cond2) OR (Cond3 AND Cond4)`
if ($level > 0) {
$input = preg_replace('/^\s*(?:NOT\b\s*)?+[(](.*)[)]\s*$/i', '\1', $input);
}
// Fetch all sub-conditions at current level:
$next_conds = '/((?:\bNOT\b\s*+)?+[^)(\s]++|(?:\bNOT\b\s*+)?+[(](?:\s*+(?1)\s*+)*+[)])/i';
preg_match_all($next_conds, $input, $matches);
// Evaluate subexpressions
foreach ($matches[0] as $match) {
split_conditions($match, $level + 1);
}
}
split_conditions($conditions);
// Trim and remove duplicates
$list_conditions = array_unique(array_map(function($x){
return preg_replace('/^\s*|\s*$/', '', $x);
}, $list_conditions));
// Add columns
$list_conditions = array_map(function($x){
return preg_replace('/([^\s()]++)(?<!\bAND\b)(?<!\bOR\b)(?<!\bNOT\b)/i', "skill='$1'", $x);
}, $list_conditions);
print "Just the conditions...\n\n";
print_r($list_conditions);
print "\n\n";
print "Method 1) Single query with multiple SUM\n\n";
$sum_conditions = implode(",\n", array_map(function($x){
return " SUM( $x )";
}, $list_conditions));
$sumSQL = "SELECT\n$sum_conditions\nFROM candidates;";
print $sumSQL . "\n\n";
print "Method 2) Multiple queries\n\n";
$queries = implode("\n", array_map(function($x){
return "SELECT count(*) from candidates WHERE $x;";
}, $list_conditions));
print $queries . "\n\n";
答案 1 :(得分:1)
虽然不是最优雅的解决方案,但WITH ROLLUP
Mysql函数可能会很有用。参见https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html
在最简单的方法中,您可以编写以下查询来捕获独特的技能:
SELECT skill, COUNT(skill) AS mycount
FROM cands
GROUP BY skill WITH ROLLUP
这将返回所有技能的总数,在总数的底部有NULL
行,如下所示:
|skill |mycount | |--------|---------| |C++ | 2 | |Java | 3 | |Python | 4 | |NULL | 9 |
通过添加布尔操作,可以获得更复杂的结果:
SELECT skill, COUNT(skill) AS mycount, SUM(IF(skill='C++' || skill='Python', 1, 0)) AS CorPython
FROM cands
GROUP BY skill WITH ROLLUP
使用第二个选项,CorPython
列将汇总-在最后的NULL
行中-总人数为“ C或Python”。您可以将此布尔部分设为必需的复杂部分。
|skill |mycount |CorPython | |--------|---------|-----------| |C++ | 2 | 2 | |Java | 3 | 0 | |Python | 4 | 4 | |NULL | 9 | 6 | <-- This is the value you want (6)
答案 2 :(得分:0)
如何使用内置的MySQL 全文搜索功能?返回值自动排名,最匹配的项位于顶部。
您可以创建一个新列,其中包含候选人的所有技能。然后在该字段上进行搜索将为您提供排名结果。
答案 3 :(得分:0)
SELECT
count(*),
sum(skill=C++),
sum(skill=UML),
sum(skill=Python),
sum(not skill=Perl)
FROM candidates WHERE TRUE
AND skill=C++
AND (FALSE
OR (FALSE
OR skill=UML
OR skill=Python)
OR (not skill=Perl)
)
答案 4 :(得分:0)
SELECT skill, COUNT(*) FROM tbl
和补码重新计算表格。要想获得更出色的表现,只需从文本字符串中删除括号,OR和AND即可获得所提到的各种技能。然后只显示那些。
但是这些都不处理(UML OR Python)
或(C++ and not Perl)
之类的不相邻内容。无论如何,您希望从示例中得到多少个计数?还有(UML OR Python) AND C++
和另外几个。
甚至都不考虑通过SQL进行解析;使用某些客户端语言。或向候选人提出问题。
代码提示
在Perl中,可以这样做:
$str =~ s{[()]|AND|OR|NOT}{ }ig;
$str =~ s{ +}{ }g;
@skills = split(' ', $str);
PHP代码将使用preg_replace
和explode
,但在其他方面类似。在您的示例中,C++ AND ((UML OR Python) OR (not Perl))
将成为数组['C ++','UML','Python','Perl']
答案 5 :(得分:0)
嗨,这没什么要提防的
$sqlresult =array ('php, html, php, c++, perl');
//that is array result from MySQL and now we need to count every term alone only in php
//now I create this
function getcount ($word, $paragraphp){
if (preg_match("/$word/i", $paragraph))
$count = 1;
else
$count = 0;
return $count;
}
foreach ( $sqlresult as $key ) {
$finalresult = array ();
$finalresult['$key'] += getcount($key, $key);
}
//now retrieve results as following
$php = " results for php word is $finalresult[php]";
$perl = "results for perl word is $finalresult[perl]";
echo $php;
echo $perl;
如果您的段落包含很多单词,则应首先使用explode php函数将其转换为数组,然后按上述步骤开始
在不合适的大项目中,您需要MySQL的良好替代品 在这种情况下,我建议使用SPHINX搜索 在SPHINX中运行查询后 运行此查询
SHOW META;
这将为您搜索的每个单词提供命中数,以获取更多详细信息,请检查此http://sphinxsearch.com/docs/current/sphinxql-show-meta.html