2011-01-19 132 views
5

我有一个房间和设备的数据库。我想查询数据库并返回一个房间列表,例如电视,收音机,坐着和冰箱(eq1,eq2,eq3,....,eqN)。查询多个EXIST

我有以下的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
select * from rooms r where 
(select count(id) from equipments where eq_id='eq1' and room_id=r.id) > 0 
and 
... 
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”

+0

它也会返回count(id)> = 2的行,只是由于eq1的行(并且可能没有包含eq_id ='eq2'的行)。即它不起作用 – Unreason 2011-01-19 10:38:22

+0

是的,当然,但如果组合“id + eq_id”是唯一的,它将起作用 – vmg 2011-01-19 10:45:33

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 AND EXISTS有机会修剪第一个false的执行分支时,上面必须实际计算不同的值(遍历所有记录)并查看该值是什么。

那么你应该考虑的是速度更快:

  • 通过关联到一个房间(一个相关子查询)或
  • 运行N(最坏情况)相关(但高度选择性的子查询)的所有记录去一次每个房间

这取决于你的数据的统计(我认为,如果大部分房间没有所有的追捧设备在他们那你最初的版本应该会更快,如果大部分房间都装备在其中那么建议的版本可能会表现更好;此外,如果EXISTS版本速度更快作出努力:第一,最有可能的查询失败稀有设备,如第一次检查)

您也可以尝试与A组版本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未经测试)

0

使用存储过程。

这里是程序的mysql:CALL GetRooms('RoomTableName','EquipmentTableName','EquipmentIDs')

例:

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('rooms','equipemnts','eq1;eq2;eq3'); 

希望这有助于。