2011-12-01 72 views
2

我有一個名爲'dealBusinessLocations'的字段(在一個表'dp_deals'中),它包含以逗號分隔的格式的另一個表(dp_business_locations)的一些ID。如何使用in()函數使用從mysql存儲函數返回的值?

dealBusinessLocations 
---------------------- 
0,20,21,22,23,24,25,26 

我需要在查詢的in()函數內使用這個值。

select * from dp_deals as d left join dp_business_locations as b on(b.businessLocID IN (d.dealBusinessLocations) ; 

正弦MySQL不支持任何字符串爆炸功能,我創建了一個存儲功能

delimiter // 
DROP FUNCTION IF EXISTS BusinessList; 
create function BusinessList(BusinessIds text) returns text deterministic 
BEGIN 
    declare i int default 0; 
    declare TmpBid text; 
    declare result text default ''; 
    set TmpBid = BusinessIds; 
    WHILE LENGTH(TmpBid) > 0 DO 
      SET i = LOCATE(',', TmpBid); 
      IF (i = 0) 
        THEN SET i = LENGTH(TmpBid) + 1; 
      END IF; 
      set result = CONCAT(result,CONCAT('\'',SUBSTRING(TmpBid, 1, i - 1),'\'\,')); 
      SET TmpBid = SUBSTRING(TmpBid, i + 1, LENGTH(TmpBid)); 
    END WHILE; 
    IF(LENGTH(result) > 0) 
     THEN SET result = SUBSTRING(result,1,LENGTH(result)-1); 
    END IF; 
    return result; 
END// 
delimiter ; 

該功能可以正常使用。

mysql> BusinessList('21,22') 
BusinessList('21,22') 
----------------------- 
'21','22' 

但是使用該函數的查詢也不起作用。這裏是查詢。

select * from dp_deals as d left join dp_business_locations as b on(b.businessLocID IN (BusinessList(d.dealBusinessLocations))); 

我已經使用功能argumet靜態值也嘗試過,但沒有用

select * from dp_deals as d left join dp_business_locations as b on(b.businessLocID IN (BusinessList('21,22'))); 

似乎有一些問題與使用從函數返回值。

+0

規範化表。在此之前,使用'FIND_IN_SET()'函數。 –

回答

3

首先,請閱讀本:

Is storing a comma separated list in a database column really that bad?
Yes, it is

然後,去和規範你的表。


現在,如果你真的不能做,否則,或直到你歸一化,使用FIND_IN_SET()功能:

select * 
from dp_deals as d 
    left join dp_business_locations as b 
    on FIND_IN_SET(b.businessLocID, d.dealBusinessLocations) 

然後,再次讀到了那篇文章。如果查詢速度慢,或者如果您有其他問題與此表,那麼你就知道爲什麼:

Is storing a comma separated list in a database column really that bad?
Yes, it is

+1

+1在數據庫中的CSV是純粹的邪惡,會直接送你到地獄。 – Johan

+2

@Johan - 更糟糕的是,它不會直接下地獄,它會讓你按照自己的方式走這條漫長的路線! – MatBailie

+0

我知道csv字段是一個大問題,但我無法更改數據庫架構。感謝您的幫助 –

0

我認爲你的問題是IN()並不期望得到一個字符串中有很多字段,但很多字段。

隨着你的函數你在發送這樣的:

WHERE something IN ('\'21\',\'22\''); /* i.e. a single text containing "'21','22'" */ 

,而不是預期的

WHERE something IN ('21','22'); 
+0

Plz檢查上面發佈的函數的輸出。即。 mysql> BusinessList('21,22') BusinessList('21,22') ----------------------- '21','22 '。它返回正確的格式。 –

+1

@SijoKurian - 你的字符串確實是你想要的格式。但@ Cylindric的答案是試圖說明的一點是,它仍然只是一個字符串。它是*不是*數字列表。僅僅因爲一個字符串碰巧有代表數字和逗號等的字符,它不會成爲許多項目的列表,它只是一個字符串,其中包含所有這些字符。你需要做的是返回* many *字符串的TABLE,而不是一個字符串。然後你可以做'WHERE x IN(SELECT * FROM function())' – MatBailie

+1

正如@Dems所說,事實並非如此。你需要返回*幾個*字符串或數字,*不*一個字符串看起來像逗號之間的幾個數字。 – Cylindric

2

簡單,使用find_in_set()代替。

SELECT * 
FROM dp_deals as d 
LEFT JOIN dp_business_locations as b 
     ON (FIND_IN_SET(b.businessLocID,d.dealBusinessLocations) > 0); 

參見:http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set

請注意,如果你刪除CSV,走出過地獄,你可以使用一個簡單的連接,如:

SELECT d.*, GROUP_CONCAT(b.dealBusinessLocation) as locations 
FROM dp_deals as d 
LEFT JOIN dp_business_location as b 
     ON (d.dealBusinessLocation = b.businessLocID); 

,這將是非常非常快,並歸爲一獎金。

+0

我認爲你有相反的順序2參數。 –

+0

我很擔心csv問題,但我無法更改數據庫設計。 find_in_set()工作正常。感謝您的幫助 –

+0

ypercube是對的 –