Разделение логической строки поиска на составные части/подсчет того, что вызывает совпадения SQL SELECT

Согласно мой предыдущий вопрос рекрутер программного обеспечения может ввести логическую текстовую строку Такие какC++ AND ((UML OR Python) OR (not Perl)), которую я переведу на SELECT * FROM candidates WHERE skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)).

[Обновление] Я выделил Такие как, потому что некоторые ответы, кажется, думают, что меня интересует только этот запрос. Это только пример. Я ищу общее решение, закодированное в PHP. Может регулярное выражение? Просто некоторый код, который находит каждый подтермин запроса, чтобы я мог запрашивать подтермины по отдельности. [/Обновлять]

Я мог бы COUNT(*) указать количество совпадений, но мне также было бы очень интересно узнать, насколько каждый «подпункт» (если это правильный термин) запроса повлиял на результат.

Например. могло быть 200 кандидатов со знанием C++, но 50 не подходили, потому что у них не было опыта работы ни с UML, ни с Python.

Итак, используя либо PHP (и rexex?), либо MySql, как я могу разбить это, чтобы увидеть, какие части поискового запроса влияют на результат?

То есть разбить skill=C++ AND ((skill=UML OR skill=Python) OR (not skill=Perl)) на COUNT(*) WHERE skill=C++ и `СЧИТАТЬ (*) ГДЕ (навык=UML ИЛИ навык=Python) и т. д.

Я не знаю, есть ли в MySql какой-то EXPLAIN для этого, но подозреваю, что нет, так что мне придется разбить SELECT, как описано, и COUNT каждый подпункт отдельно.

Я надеюсь, что объяснил это ясно; если нет, попросите разъяснений. я просто не знаю с чего начать

Вы можете просто запустить отдельный запрос для отдельных условий, которые вас интересуют, верно?

CAustin 09.04.2019 20:51

Лолкс. Да, но в этом и суть вопроса - как разбить сложный запрос на составляющие его условия?

Mawg says reinstate Monica 10.04.2019 11:09

Вам нужно будет написать парсер. Это задача не на один вечер.

Paul Spiegel 18.04.2019 13:21

Это несколько оффтоп и, возможно, глупый вопрос, но почему кто-то хочет, чтобы человек нет имел опыт в какой-то теме?

Julio 19.04.2019 19:35

покажите нам, что вы пробовали, чтобы мы могли вам помочь. мы здесь не для того, чтобы писать код для вас

A.Marwan 22.04.2019 12:47

Ваш лучший выбор — это таблица сопоставления, в которой каждый навык находится в отдельной записи, и вы меняете ввод на что-то более стандартное, например C++ UML Python -Perl, где - подразумевает НЕ. Это используется большинством поисковых систем, и большинство пользователей понимают это. Принуждение пользователя к созданию ввода, например C++ AND ((UML OR Python) OR (not Perl)), создаст ужасный пользовательский опыт, и большинство пользователей этого не поймут. Затем вы можете легко проверить, соответствует ли запись в вашей таблице каждому критерию, сгенерировав некоторый `MAX (skill = 'criteria') и сложив их вместе, чтобы увидеть, соответствует ли он количеству критериев.

drakin8564 22.04.2019 16:29

Извините, но конечный пользователь попросил меня указать этот синтаксис. Вероятно, потому что это синтаксис поиска Google

Mawg says reinstate Monica 22.04.2019 17:09

@Mawg, награда заканчивается завтра :) У вас была возможность оценить ответы? (Я отредактировал свой день назад или около того, чтобы добавить логическое разделение, на случай, если вы этого не заметили)

Julio 24.04.2019 01:25

Ваш вопрос мне интересен, я заметил, что вы хотите регулярное выражение и только php. в любом случае, я ответил на него, и это мой первый раз, когда я пишу полный сценарий в качестве ответа в stackoverflow или на любом другом форуме. Я не тестировал сценарий, но он должен работать. Ваш вопрос хорош, но не подходит для этого сообщества, так как участники здесь для помощи и общих идей, а не для написания сценариев.

Creative87 24.04.2019 01:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
9
471
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Как насчет использования встроенных возможностей поиска MySQL полный текст? Возврат автоматически ранжируется с лучшими совпадениями вверху.

Вы можете создать новый столбец, содержащий все навыки и умения кандидата. Затем поиск по этому полю даст ранжированные результаты.

Функции полнотекстового поиска

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)
)

Хотя этот код может дать ответ на вопрос, предоставление дополнительного контекста относительно того, почему и/или как этот код отвечает на вопрос, повышает его ценность в долгосрочной перспективе.

ahoffner 19.04.2019 01:04

На самом деле, как ОП, я должен сказать, что это не отвечает на вопрос. Он отвечает на пример, который я привел в вопросе, но будет полезно только общее решение. Возможно, мне нужно отредактировать вопрос, чтобы уточнить, что

Mawg says reinstate Monica 19.04.2019 08:18
  1. Пересчитайте таблицу из SELECT skill, COUNT(*) FROM tbl и дополнений.
  2. Предоставьте полную таблицу с шага 1; пусть рекрутер просмотрит список.

Чтобы стать более интересным, просто удалите скобки, ИЛИ и И из текстовой строки, чтобы получить различные упомянутые навыки. Затем отображать только те.

Но ни один из них не обрабатывает (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']

Ответ принят как подходящий

Нам нужен метод разделения условий. Однако мы не можем разделить AND и OR на равные, потому что И имеют более высокий приоритет, чем ИЛИ..

Итак, в таком примере:

Cond1 AND Cond2 OR Cond3

Мы не можем разделить на AND|OR, потому что нам не хватает Cond1 AND Cond2 в целом.

Итак, первое, что нужно сделать, это добавить дополнительные круглые скобки (с регулярными выражениями) там, где это необходимо, чтобы следующий алгоритм правильно разделил условия. В предыдущем примере это было бы (Cond1 AND Cond2) OR Cond3.

После настройки мы используем регулярное выражение для получения условий для текущего уровня. Нам нужно использовать рекурсивные регулярные выражения, чтобы обнаружить открывающую/закрывающую скобку.

Каждое условие сохраняется в массиве, а затем отправляется на обработку (рекурсивно). Это связано с тем, что некоторые условия могут быть сложными и иметь вложенные условия.

Все эти условия и подусловия хранятся в массиве.

Когда у вас есть все условия (и подусловия), у вас есть две альтернативы для монтирования SQL.

Первый вариант — это один запрос без предложения WHERE и одна сумма SUM для каждого условия. Это, вероятно, лучше всего, если в таблице не так много строк.

Второй вариант — запуск нескольких запросов SELECT count(*) со всеми условиями.

Я оставляю здесь php-код. Я также добавил возможность настроить максимальное количество уровней гнезда при разделении условий.

У вас есть демо на Идеоне, здесь.

<?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";

К вашему сведению @mawg, я изменил свой ответ, чтобы дать вам код, который должен иметь возможность разделять любые условия на любом уровне вложенности, а также должен заботиться о приоритете И / ИЛИ. Код также выведет две опции для SQL.

Julio 23.04.2019 02:45

Привет, это не большое дело, берегись

$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;

Если у вас есть абзац с большим количеством слов, вы должны сначала преобразовать его в массив с функцией взрыва php и начать шаги, как указано выше.

В большом проекте, который не подходит, вам нужна хорошая замена MySQL. В этом случае я предлагаю поиск SPHINX После запуска запроса в SPHINX Запустите этот запрос

SHOW META;

Это даст каждое слово в вашем поиске с количеством попаданий, для получения более подробной информации проверьте этот http://sphinxsearch.com/docs/current/sphinxql-show-meta.html

Хотя это и не самое элегантное решение, функция WITH ROLLUPMysql может оказаться полезной. См. 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)

Другие вопросы по теме