查询多个EXIST

时间:2011-01-19 10:10:12

标签: mysql exists

我有一个房间和设备数据库。我想查询数据库并返回一个房间列表,例如电视,收音机,坐着和冰箱(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)

有没有办法优化或缩短它?

5 个答案:

答案 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上修剪执行分支,上面必须实际计算不同的值(遍历所有记录)和看看那是什么价值。

所以你应该考虑更快的事情:

  • 查看与房间相关的所有记录(一个相关子查询)或
  • 为每个房间运行N(最差情况)相关(但高度选择性的子查询)

这取决于您的数据的统计数据(我认为如果大多数房间没有所有寻求的设备,那么您的初始版本应该更快,如果大多数房间都有所有设备,那么建议的版本可能表现更好;如果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)

要更快地执行查询,请使用 Exists

select * 
from rooms as r 
where exists (
select * 
from equipments 
where eq_id IN ('eq1','eq2',..,'eqN') and r.id= equipments.room_id);