我有一个房间和设备数据库。我想查询数据库并返回一个房间列表,例如电视,收音机,坐着和冰箱(eq1,eq2,eq3,....,eqN)。
我有以下SELECT语句:
select * from rooms r where
exists (select id from equipments where eq_id='eq1' and room_id=r.id)
and
exists (select id from equipments where eq_id='eq2' and room_id=r.id)
and
exists (select id from equipments where eq_id='eq3' and room_id=r.id)
.......
and
exists (select id from equipments where eq_id='eqN' and room_id=r.id)
有没有办法优化或缩短它?
答案 0 :(得分:3)
缩短你可以
select *
from rooms r
where @N = (select count(distinct eq_id)
from equipments
where eq_id IN ('eq1','eq2',...,'eqN') and room_id=r.id)
修改强> 但不确定它是否真的会让它更快......恰恰相反,带有EXISTS和EXISTS的版本有机会在第一个false上修剪执行分支,上面必须实际计算不同的值(遍历所有记录)和看看那是什么价值。
所以你应该考虑更快的事情:
这取决于您的数据的统计数据(我认为如果大多数房间没有所有寻求的设备,那么您的初始版本应该更快,如果大多数房间都有所有设备,那么建议的版本可能表现更好;如果EXISTS版本更快,则首先尝试最有可能失败的查询,即首先检查最稀有设备)
您也可以尝试使用GROUP BY
的版本select r.*
from rooms r join
equipments e on r.id = e.room_id
group by r.id
where eg_id in ('eq1','eq2',...,'eqN')
having count(distinct e.eq_id) = @N
(以上SQL未经测试)
答案 1 :(得分:1)
试试这个(我没有任何可用的数据库来测试它,也考虑性能)
select * from
rooms r,
(
select count(distinct id) as cnt, id from equipments where eq_id in ('eq1','eq2') group by id
) as sub
where sub.id = r.id
and sub.cnt >= 2 'Options count
注意:2 - 这是您需要的选项数量。例如,它们是:'eq1','eq2'
答案 2 :(得分:0)
select * from rooms r where
(select count(id) from equipments where eq_id='eq1' and room_id=r.id) > 0
and
...
答案 3 :(得分:0)
使用存储过程。
这是mysql的程序:
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `GetRooms`(IN roomtable TEXT, IN equipmenttable TEXT, IN equipments TEXT )
BEGIN
DECLARE statement text;
DECLARE Pos int;
DECLARE cond text;
DECLARE element text;
DECLARE tmpTxt text;
set tmpTxt = equipments;
set cond = "";
set Pos = instr(tmpTxt,';');
while Pos <> 0 do
set element = substring(tmpTxt, 1, Pos-1);
if cond <> "" then
set cond = concat(cond,' and ');
end if;
set cond = concat(cond,'exists (select id from ' , equipmenttable ,' where eq_id=''' , element ,''' and room_id=r.id) ');
set tmpTxt = replace(tmpTxt, concat(element,';'), '');
set Pos = instr(tmpTxt,';');
end while;
if tmpTxt <> "" then
if cond <> "" then
set cond = concat(cond,' and ');
end if;
set cond = concat(cond,'exists (select id from ' , equipmenttable ,' where eq_id=''' , tmpTxt ,''' and room_id=r.id) ');
end if;
SET @statement = concat('Select * FROM ' , roomtable , " WHERE " , cond , ";");
PREPARE stmt FROM @statement;
EXECUTE stmt;
END
执行:CALL GetRooms('RoomTableName','EquipmentTableName','EquipmentIDs')
示例:
Call GetRooms('rooms','equipemnts','eq1;eq2;eq3');
希望这有帮助。
答案 4 :(得分:0)
select *
from rooms as r
where exists (
select *
from equipments
where eq_id IN ('eq1','eq2',..,'eqN') and r.id= equipments.room_id);