我在使用动态SQL搜索查询时遇到了一些麻烦,在该查询中,我希望能够找到具有要搜索的任何字段的所有对象。下面是数据结构。
objectregister fieldvalue
| id | name | | id | objid | fieldid | value (illustration) |
+----+---------+ +----+---------+---------+------------------------+
| 1 | CUBE | | 1 | 1 | 12 | 4 (BLUE) |
| 2 | SQUARE | | 2 | 2 | 12 | 4 (BLUE) |
| 3 | 1 | 22 | 27 (SMALL) |
| 4 | 2 | 22 | 9 (BIG) |
具有数据库结构的测试平台:
CREATE TABLE IF NOT EXISTS `objectregister` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(1024) COLLATE utf8_swedish_ci NOT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `objectregister` (`id`, `name` ) VALUES
(1, 'CUBE'),
(2, 'SQUARE');
CREATE TABLE IF NOT EXISTS `fieldvalue` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`objid` int(11) NOT NULL,
`fieldid` int(11) NOT NULL,
`value` varchar(2048) COLLATE utf8_swedish_ci NOT NULL,
UNIQUE KEY `id` (`id`)
);
INSERT INTO `fieldvalue` (`id`, `objid`, `fieldid`, `value`) VALUES
(1, 1, 12, 4),
(2, 2, 12, 4),
(3, 1, 22, 27),
(4, 2, 22, 9);
SELECT `id`, `name` FROM `objectregister` WHERE id IN
(
SELECT * FROM
(
SELECT `objid`
FROM `fieldvalue`
WHERE 1 AND ( (fieldvalue.fieldid = '12' AND fieldvalue.value = '4') OR (fieldvalue.fieldid = '22' AND fieldvalue.value = '27') )
GROUP BY objid
) as subquery
)
+----+--------+
| id | name |
+----+--------+
| 1 | CUBE |
| 2 | SQUARE |
+----+--------+
https://rextester.com/XTR72354
示例:
我想找到所有蓝色的对象。在这种情况下:立方体,正方形
我想找到所有 blue 和 big 的对象。在这种情况下:SQUARE
因此,我想我首先需要选择与子查询中的任何搜索匹配的所有可能的 objid 。将它们放在一行中,这样我以后可以在哪里选择它们都匹配的地方?但是我该怎么做呢?我需要多个SUB查询联合吗? GROUP_CONCAT? TEMP表?
这是我撰写本文时的查询的当前阶段(它将在子查询中返回两行,但在外部查询上需要WHERE):
SELECT `id`, `name` FROM `objectregister` WHERE id IN
(
SELECT * FROM
(
SELECT `objid`
FROM `fieldvalue`
WHERE 1 AND ( (fieldvalue.fieldid = '12' AND fieldvalue.value = '4') OR (fieldvalue.fieldid = '22' AND fieldvalue.value = '27') )
GROUP BY objid
) as subquery
)
答案 0 :(得分:1)
一种选择是使用exists
:
select r.*
from objectregister r
where
exists (
select 1 from fieldvalue f where f.objid = r.id and f.fieldid = 12 and f.value = 4
) and exists (
select 1 from fieldvalue f where f.objid = r.id and f.fieldid = 22 and f.value = 27
)
使用fieldvalue(objid, fieldid, value)
上的索引,这应该是一个有效的解决方案。
您可以使用having
子句来加入,聚合和过滤:
select r.id, r.name
from objectregister r
inner join fieldvalue f on f.objid = r.id
group by r.id, r.name
having max(f.fieldid = 12 and f.value = 4) = 1 and max(f.fieldid = 22 and f.value = 27) = 1
答案 1 :(得分:0)
类似地...
SELECT o.*
FROM objectregister o
JOIN fieldvalue v
ON v.objid = o.id
WHERE value IN (4,9)
GROUP
BY o.id
HAVING COUNT(DISTINCT value) = 2;
如果值在不同的上下文中具有不同的含义,那么您还需要字段ID。一种简短(但效率低下的写作方式,WHERE (fieldid,value) IN((12,4),(etc))
答案 2 :(得分:0)
EAV模式有很多问题。
对于fieldvalue
,请摆脱id
,而改为PRIMARY KEY(objid, fieldid)
。
也为fieldvalue
拥有INDEX(fieldid)
。 (由于时间太长,可能不值得添加value
。)
避免使用IN ( SELECT ... )
;更改为JOIN .. ON
或EXISTS( SELECT 1 ... )
我想找到所有蓝色的对象。在这种情况下:立方体,正方形
SELECT obj.name
FROM ( SELECT objid
FROM fieldvalue
WHERE fieldid = '12'
AND `value` = '4'
) AS x
JOIN objectregister AS obj ON x.objid = obj.id;
或者,将第一行更改为
SELECT GROUP_CONCAT(obj.name)
我想找到所有蓝色和大的物体。在这种情况下:SQUARE
SELECT obj.name
FROM ( SELECT objid FROM fieldvalue WHERE fieldid = '12' AND `value` = '4' ) AS x
JOIN ( SELECT objid FROM fieldvalue WHERE fieldid = '22' AND `value` = '27' ) AS y
USING(objid)
JOIN objectregister AS obj ON x.objid = obj.id;
这里的哲学可能是“从您知道的开始;朝着您需要知道的方向努力”,而不是“让我们检查每个对象以查看哪些对象适用”。