从两个左连接中过滤数据

Filter data from two left joins

我有一些简化的数据:

mysql> SELECT * FROM tbl_task;
+----+----------+
| id | data     |
+----+----------+
|  1 | data 1   |
|  2 | data 2   |
|  3 | data 3   |
|  4 | data 4   |
|  5 | data 55  |
|  6 | data 166 |
+----+----------+

mysql> SELECT * FROM tbl_parameter;
+----+---------+----------+
| id | task_id | name     |
+----+---------+----------+
|  1 |       1 | hardware |
|  2 |       1 | hardware |
|  3 |       1 | hardware |
|  4 |       2 | hardware |
|  5 |       2 | hardware |
|  6 |       3 | hardware |
|  7 |       3 | hardware |
|  8 |       3 | hardware |
|  9 |       4 | hardware |
| 10 |       5 | hardware |
| 11 |       5 | hardware |
| 12 |       5 | hardware |
| 13 |       6 | hardware |
| 14 |       6 | hardware |
+----+---------+----------+

mysql> SELECT * FROM tbl_parameter_value;
+----+--------------+---------+
| id | parameter_id | value   |
+----+--------------+---------+
|  1 |            1 | modem   |
|  2 |            2 | printer |
|  3 |            3 | 220     |
|  4 |            4 | 24      |
|  5 |            5 | modem   |
|  6 |            6 | printer |
|  7 |            7 | 220     |
|  8 |            8 | gps     |
|  9 |            9 | 24      |
| 10 |           10 | printer |
| 11 |           11 | modem   |
| 12 |           12 | 220     |
| 13 |           13 | 24      |
| 14 |           14 | modem   |
+----+--------------+---------+

所以,任务有多个参数,每个参数有一个值。看起来似乎没有意义,但这只是简化的数据。

我使用两个连接来获取 value 数据:

mysql> SELECT tbl_task.id, tbl_parameter_value.value
    -> FROM tbl_task
    -> LEFT JOIN tbl_parameter ON tbl_task.id = tbl_parameter.task_id
    -> LEFT JOIN tbl_parameter_value ON tbl_parameter.id = tbl_parameter_value.parameter_id;
+----+---------+
| id | value   |
+----+---------+
|  1 | modem   |
|  1 | printer |
|  1 | 220     |
|  2 | 24      |
|  2 | modem   |
|  3 | printer |
|  3 | 220     |
|  3 | gps     |
|  4 | 24      |
|  5 | printer |
|  5 | modem   |
|  5 | 220     |
|  6 | 24      |
|  6 | modem   |
+----+---------+

如您所见,task.id 列中有一些重复项。我需要的是将此查询过滤为 return 仅同时具有参数值 modem AND printer 的任务。

以下查询显然没有任何意义:

SELECT tbl_task.id, tbl_parameter_value.value
FROM tbl_task
LEFT JOIN tbl_parameter ON tbl_task.id = tbl_parameter.task_id
LEFT JOIN tbl_parameter_value ON tbl_parameter.id = tbl_parameter_value.parameter_id
WHERE value LIKE '%modem%' AND value LIKE '%printer%'

我也试过:

SELECT tbl_task.id, tbl_parameter_value.value
FROM tbl_task
LEFT JOIN tbl_parameter ON tbl_task.id = tbl_parameter.task_id
LEFT JOIN tbl_parameter_value ON tbl_parameter.id = tbl_parameter_value.parameter_id AND tbl_parameter_value.value LIKE '%modem%' OR tbl_parameter_value.value LIKE '%printer%'

它给出了错误的结果。

如何同时过滤具有调制解调器和打印机参数值的不同任务?
根据这些数据我需要得到的是:

+----+
| id |
+----+
|  1 |
|  5 |
+----+

由于需要查找参数值为modemANDprinter的任务,因此需要加入tablestbl_parametertbl_parameter_value 在查询中两次(使用 table 别名):

SELECT t.id
FROM tbl_task t
INNER JOIN tbl_parameter tp1 ON t.id = tp1.task_id
INNER JOIN tbl_parameter tp2 ON t.id = tp2.task_id
INNER JOIN tbl_parameter_value tpv1 ON tp1.id = tpv1.parameter_id
INNER JOIN tbl_parameter_value tpv2 ON tp2.id = tpv2.parameter_id
WHERE tpv1.value LIKE '%modem%' AND tpv2.value LIKE '%printer%'

如果你想测试参数值是否完全等于modemprinter,你可以将WHERE子句替换为:

WHERE tpv1.value = 'modem' AND tpv2.value = 'printer'

注意:如果您使用 LEFT JOIN 而不是 INNER JOIN,查询将始终 return 来自 id 的所有值tbl_task。这显然不是预期的结果。

阅读 documentation about the JOIN syntax 以了解更多信息。