2011-12-01 44 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是对的 –