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