在PHP中将布尔表达式解析为MySQL查询-第2部分

在PHP中将布尔表达式解析为MySQL查询-第2部分,php,mysql,parsing,Php,Mysql,Parsing,我正在为一个朋友编写一个应用程序,SQL不是我的强项。我认为我已经把这件事交给了我的律师,律师得到了极好的答复 然而,我的朋友再次移动了球门柱(并发誓这次是最后一次) 考虑到这些表格 mysql> describe skill_names; +------------+----------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra

我正在为一个朋友编写一个应用程序,SQL不是我的强项。我认为我已经把这件事交给了我的律师,律师得到了极好的答复

然而,我的朋友再次移动了球门柱(并发誓这次是最后一次)

考虑到这些表格

mysql> describe skill_names;
+------------+----------+------+-----+---------+----------------+
| Field      | Type     | Null | Key | Default | Extra          |
+------------+----------+------+-----+---------+----------------+
| skill_id   | int(11)  | NO   | PRI | NULL    | auto_increment |
| skill_name | char(32) | NO   | MUL | NULL    |                |
+------------+----------+------+-----+---------+----------------+

mysql> describe skill_usage;
+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| skill_id | int(11) | NO   | MUL | NULL    |       |
| job_id   | int(11) | NO   | MUL | NULL    |       |
+----------+---------+------+-----+---------+-------+

mysql> describe jobs;
+--------------+---------+------+-----+---------+----------------+
| Field        | Type    | Null | Key | Default | Extra          |
+--------------+---------+------+-----+---------+----------------+
| job_id       | int(11) | NO   | PRI | NULL    | auto_increment |
| candidate_id | int(11) | NO   | MUL | NULL    |                |
| company_id   | int(11) | NO   | MUL | NULL    |                |
| start_date   | date    | NO   | MUL | NULL    |                |
| end_date     | date    | NO   | MUL | NULL    |                |
+--------------+---------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
用户输入用于技能搜索的文本

一些例子可能是

  • C
  • C或C++
  • C++与UML
  • (C和内核)或(C++和UML)
我想用PHP解析它并生成一个适当的SQL查询。我的答案大致相同,但需要调整

以前,我认为如果用户输入两种技能并对它们进行and运算,例如
C++和UML
,那么我应该返回使用这两种技能的任何工作的详细信息

现在,他说,他只希望应聘者能同时使用这两种技能(因此使用AND),但不一定在同一份工作上。为了澄清这一点,我的PHP API将返回一个候选数组,其中每个条目都有一个作业数组

为了实现这一点,我想调整前面问题答案中的代码。我想知道我是否会最终用PHP完成整个工作,使用一堆嵌套的FOR循环,而不是将其卸载到SQL引擎上

更新 我找不到一个同时支持PHP和MySQL的好网站

如果有人想在本地主机上测试自己的代码,测试数据库的主要部分如下所示:

测试搜索
3.1.5(Python和UML)或(C++或UML)

下面是创建测试数据库的SQL脚本:

CREATE TABLE `candidates` (
  `candidate_id` INT(11) NOT NULL AUTO_INCREMENT,
  `candidate_name` CHAR(50),
  `candidate_city` CHAR(50),
  `latitude` DECIMAL(11,8),
  `longitude` DECIMAL(11,8),
     PRIMARY KEY (candidate_id));

CREATE TABLE `companies` (
  `company_id` INT(11) NOT NULL AUTO_INCREMENT,
  `company_name` CHAR(50) NOT NULL,
  `company_city` CHAR(50) NOT NULL,
  `company_post_code` CHAR(50) NOT NULL,
  `latitude` DECIMAL(11,8) NOT NULL,
  `longitude` DECIMAL(11,8) NOT NULL,
     PRIMARY KEY (company_id));

CREATE TABLE `jobs` (
  `job_id` INT(11) NOT NULL AUTO_INCREMENT,
  `candidate_id` INT(11) NOT NULL,
  `company_id` INT(11) NOT NULL,
  `start_date` DATE NOT NULL,
  `end_date` DATE NOT NULL,
     PRIMARY KEY (job_id));


CREATE TABLE `skill_names` (
  `skill_id` INT(11) NOT NULL AUTO_INCREMENT,
  `skill_name` CHAR(32) NOT NULL,
     PRIMARY KEY (skill_id));


CREATE TABLE `skill_usage` (
  `skill_id` INT(11) NOT NULL,
  `job_id` INT(11) NOT NULL);

INSERT INTO `skill_names` (skill_name) VALUES("C");
INSERT INTO `skill_names` (skill_name) VALUES("Python");
INSERT INTO `skill_names` (skill_name) VALUES("C++");
INSERT INTO `skill_names` (skill_name) VALUES("UML");

INSERT INTO `candidates` (candidate_name, candidate_city, latitude, longitude ) VALUES("One",   "Hastings",   50.8543, 0.5735);
INSERT INTO `candidates` (candidate_name, candidate_city, latitude, longitude ) VALUES("Two",   "Slough",  51.5105, 0.5950);
INSERT INTO `candidates` (candidate_name, candidate_city, latitude, longitude ) VALUES("Three", "Stonehenge", 51.1789, -1.8262);

INSERT INTO `companies` (company_name, company_city, company_post_code, latitude, longitude ) VALUES("Thales", "Crawley",   "AB1 1CD", 51.1091, -0.1872);
INSERT INTO `companies` (company_name, company_city, company_post_code, latitude, longitude ) VALUES("BAe",    "Rochester", "EF1 2GH", 51.3880, 0.5067);
INSERT INTO `companies` (company_name, company_city, company_post_code, latitude, longitude ) VALUES("Google", "East Ham",  "E6  0XX", 51.5334, 0.0499);

INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(1, 1, "2015-01-010", "2015-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(1, 2, "2016-01-010", "2016-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(1, 3, "2017-01-010", "2017-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(2, 2, "2015-01-010", "2015-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(2, 3, "2020-01-010", "2020-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(2, 3, "2011-01-010", "2011-12-31");
INSERT INTO `jobs` (candidate_id, company_id, start_date, end_date ) VALUES(3, 1, "2019-01-010", "2019-12-31");

INSERT INTO `skill_usage` (job_id, skill_id) VALUES(1, 1);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(2, 2);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(3, 3);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(4, 3);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(5, 2);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(6, 3);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(6, 4);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES(7, 2);
INSERT INTO `skill_usage` (job_id, skill_id) VALUES (7, 4);

DB FIDLE中的工作查询示例:

(C和内核)或(C++和UML)
的输出示例:

参数数组:

Array
(
    [arg_0] => C
    [arg_1] => kernel
    [arg_2] => C++
    [arg_3] => UML
)

我之所以投票结束这个问题,是因为我试图不费吹灰之力就摆脱困境。好吧,我在测试数据库中投入了大量的精力,现在我已经将其附在了测试数据库中(问题结束后,唉)。不可见的努力还包括为我的SQL课程付费,但这真的不是我的辖区,所以S.O是我唯一的希望。有重新开放的机会吗?我将尝试拼凑一些代码,如果它接近,也许有人可以改进它。我对链接中原始问题的答案可以很容易地修改,生成的部分作为标量相关子查询。再说一次:转储DDL并询问SQL不是问题。所以,这不是一个代码编写服务。这可能是我以前的问题的重复,这是第2部分。我甚至连上面的链接都没有,我已经收回了我的否决票。不过,您的答案看起来不完整(什么是查找集中的查找?)另外:您的查询似乎对SQL注入很敏感。
find\u in\u set()
是mysql函数。代码工作并检索@mawgsaysrestemonica想要的内容。我不理解人们的否决,只是因为他们不知道特定的mysql函数或sql注入。当然这很敏感,因为这不是问题的目的。我甚至不知道使用了什么ORM系统。@Tajni:这是元效应,你的答案是从这里链接的:
$string = '(C AND kernel) OR (C++ AND UML)';

//Adding spaces between parentheses to accept inputs without that space as well
$string = str_replace('(', ' ( ', $string);
$string = str_replace(')', ' ) ', $string);

//Splitting input into separate strings, taken from previous question
$tokens = preg_split('/[\s]+/', $string);

$query = '';

$args = [];
$n = 0;
//Transcripting all strings separately and each skill name into FIND_IN_SET function
foreach ($tokens as $tok) {
    switch ($tok) {
        case '':  # skip empty tokens
        case ';':  # No, you should not!
        case '"':
        case "'":
        case ';':
            break;
        case '(':
            $query .= '(';
            break;
        case ')':
            $query .= ')';
            break;
        case '&':
        case 'AND':
            $query .= ' AND ';
            break;
        case '|':
        case 'OR':
            $query .= ' OR ';
            break;
        case '!':
        case 'NOT':
            $query .= ' NOT ';
            break;
        default:
            $arg = 'arg_' . $n;
            $args[$arg] = $tok;
            $query .= "FIND_IN_SET(':{$arg}', skills)";
            $n++;
            break;
    }
}

//Query grouping all of the skills used by candidates returning candidates
//with grouped column skills with HAVING clause containing all of the
//conditions they must match. So query returns only candidates who have ever
//used desired skills.
$sql = "SELECT candidate_id, GROUP_CONCAT(DISTINCT skill_names.skill_name) as skills
FROM jobs
LEFT JOIN skill_usage ON skill_usage.job_id = jobs.job_id
LEFT JOIN skill_names ON skill_names.skill_id = skill_usage.skill_id
GROUP BY candidate_id
HAVING {$query}
ORDER BY candidate_id DESC";
SELECT candidate_id, GROUP_CONCAT(DISTINCT skill_names.skill_name) as skills
FROM jobs
    LEFT JOIN skill_usage ON skill_usage.job_id = jobs.job_id
    LEFT JOIN skill_names ON skill_names.skill_id = skill_usage.skill_id
GROUP BY candidate_id
HAVING (FIND_IN_SET('C', skills) AND FIND_IN_SET('kernel', skills)) OR (FIND_IN_SET('C++', skills) AND FIND_IN_SET('UML', skills))
ORDER BY candidate_id DESC
Array
(
    [arg_0] => C
    [arg_1] => kernel
    [arg_2] => C++
    [arg_3] => UML
)