2011-01-19 59 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'); 

希望這有助於。