我有一个在PHP中动态构建的查询,它使用一组连接在一起的子查询来选择对象值的不同组合...例如,给定值表:
[object_id] [value_id]
99 1
99 2
99 3
我会得到以下结果:
[object_id] [a0] [a1] [a2]
99 null null null // empty is a valid combination
99 1 null null
99 null 2 null
99 null null 3
99 1 2 null
99 null 2 3
99 1 2 3
我有一个单独的表,列出了这些对象值的无效组合:
INVALID_VALUES
[object_id] [value]
99 1
99 2
我正在尝试使用无效值列表来过滤第一个查询的结果。更具体地说,如果2个或更多 a*
列作为invalid_values
中的值存在,则不包括该行。因此,使用此示例,结果中不会包含1 2 null 99
和1 2 3 99
,因为1& 2在记录中并且是无效值。
我有一个查询能够满足我的需求,但我担心它效率很低。对于我正在构建的每个子查询,我加入另一个子查询,该子查询选择逗号分隔的无效值。我用它来表明值列是否是“不兼容的候选者”。在所有这些结束时,我将所有不兼容的候选列加起来,如果它是2或更多,则它们不会被返回。以下是为“object”id 99:
构建的查询示例SELECT a0.value_id AS '0', a1.value_id AS '1', a2.value_id AS '2'
FROM (
SELECT NULL AS value_id, 99 AS object_id, 0 AS incompatible_candidate
UNION ALL
SELECT value.value_id, value.object_id, CASE WHEN FIND_IN_SET(value.value_id, pivs.valueIds) THEN 1 ELSE 0 END AS incompatible_candidate
FROM value
JOIN (
SELECT GROUP_CONCAT(iv.value_id ORDER BY iv.value_id ASC) AS valueIds
FROM invalid_values iv
WHERE iv.object_id = 99
GROUP BY iv.object_id
) pivs
WHERE value.value_id IN (1) AND value.object_id = 99
) AS a0
JOIN (
SELECT NULL AS value_id, 99 AS object_id, 0 AS incompatible_candidate
UNION ALL
SELECT value.value_id, value.object_id, CASE WHEN FIND_IN_SET(value.value_id, pivs.valueIds) THEN 1 ELSE 0 END AS incompatible_candidate
FROM value
JOIN (
SELECT GROUP_CONCAT(iv.value_id ORDER BY iv.value_id ASC) AS valueIds
FROM invalid_values iv
WHERE iv.object_id = 99
GROUP BY iv.object_id
) pivs
WHERE value.value_id IN (2) AND value.object_id = 99
) AS a1
JOIN (
SELECT NULL AS value_id, 99 AS object_id, 0 AS incompatible_candidate
UNION ALL
SELECT value.value_id, value.object_id, CASE WHEN FIND_IN_SET(value.value_id, pivs.valueIds) THEN 1 ELSE 0 END AS incompatible_candidate
FROM value
JOIN (
SELECT GROUP_CONCAT(iv.value_id ORDER BY iv.value_id ASC) AS valueIds
FROM invalid_values iv
WHERE iv.object_id = 99
GROUP BY iv.object_id
) pivs
WHERE value.value_id IN (3) AND value.object_id = 99
) AS a2
GROUP BY a0.value_id, a1.value_id, a2.value_id
HAVING SUM(a0.incompatible_candidate + a1.incompatible_candidate + a2.incompatible_candidate) < 2;
有人可以帮我构建更有效的查询吗?
答案 0 :(得分:1)
使用排列表检测无效行,即具有两个或更多无效值的行。您可以更改为有效行的< 2
。
<强> SQL DEMO 强>
SELECT *
FROM Permutation P
LEFT JOIN Invalid x
ON (P.`a0`, P.`object_id`) = (x.`value_id`, x.`object_id`)
LEFT JOIN Invalid y
ON (P.`a1`, P.`object_id`) = (y.`value_id`, y.`object_id`)
LEFT JOIN Invalid z
ON (P.`a2`, P.`object_id`) = (z.`value_id`, z.`object_id`)
AND P.`object_id` = z.`object_id`
WHERE CASE WHEN x.`value_id` IS NULL THEN 0 ELSE 1 END +
CASE WHEN y.`value_id` IS NULL THEN 0 ELSE 1 END +
CASE WHEN z.`value_id` IS NULL THEN 0 ELSE 1 END
>= 2
;
<强>输出强>