在MySQL“IN”子句中用逗号分隔值

我的桌子上有一列,里面存放着多个由逗号分隔的ID。 有没有一种方法可以在查询的“IN”子句中使用此列的值。

列( city )具有像6,7,8,16,21,2

我需要使用

 select * from table where e_ID in (Select city from locations where e_Id=?) 

我对Crozin的答案感到满意,但我愿意接受build议,意见和select。

随意分享您的意见。

基于@Jeremy Smith的FIND_IN_SET()例子,你可以用一个连接来完成,所以你不必运行一个子查询。

 SELECT * FROM table t JOIN locations l ON FIND_IN_SET(t.e_ID, l.city) > 0 WHERE l.e_ID = ? 

这被称为性能很差,因为它必须执行表扫描,对tablelocations 每个行的组合评估FIND_IN_SET()函数。 它不能使用索引,也没有办法改进它。

我知道你说过你正在努力做好一个糟糕的数据库devise,但是你必须明白这是多么糟糕。

说明:假设我要求你在电话簿中查找所有人,其中第一个,中间或最后一个首字母是“J”。 在这种情况下,本书的sorting顺序是无法帮助的,因为无论如何您都必须扫描每一页。

@fthiella给出的LIKE解决scheme在性能方面也有类似的问题。 它不能被索引。

另请参阅我的答案在数据库列中存储分隔列表真的很糟糕? 对于存储非规范化数据的这种方式的其他缺陷。

如果您可以创build补充表来存储索引,则可以将位置映射到城市列表中的每个条目:

 CREATE TABLE location2city ( location INT, city INT, PRIMARY KEY (location, city) ); 

假设你有一个查找表的所有可能的城市(不只是在table提到的那些),你可以忍受一次低效率产生的映射:

 INSERT INTO location2city (location, city) SELECT l.e_ID, c.e_ID FROM cities c JOIN locations l ON FIND_IN_SET(c.e_ID, l.city) > 0; 

现在,您可以运行更高效的查询来查找表中的条目:

 SELECT * FROM location2city l JOIN table t ON t.e_ID = l.city WHERE l.e_ID = ?; 

这可以使用索引。 现在您只需要注意位置中的任何INSERT / UPDATE / DELETE行也会在locations插入相应的映射行。

从MySQL的angular度来看,你不会存储多个以逗号分隔的id,而是存储一个文本值,它与“Hello World”或“我喜欢蛋糕”完全相同。 – 即它没有任何意思。

你必须做的是创build一个分离的表,将数据库中的两个对象链接在一起。 在基于SQL的数据库中阅读有关多对多或一对多 (取决于您的要求)关系的更多信息。

而不是在你的查询中使用IN ,使用FIND_IN_SET ( docs ):

 SELECT * FROM table WHERE 0 < FIND_IN_SET(e_ID, ( SELECT city FROM locations WHERE e_ID=?)) 

关于第一种forms规范化的常见警告(数据库不应该在一个列中存储多个值),但如果你坚持使用它,那么上面的语句应该会有所帮助。

这不使用IN子句,但它应该做你所需要的:

 Select * from table where CONCAT(',', (Select city from locations where e_Id=?), ',') LIKE CONCAT('%,', e_ID, ',%') 

但是您必须确保e_ID不包含任何逗号或任何快乐字符。

例如

 CONCAT(',', '6,7,8,16,21,2', ',') returns ',6,7,8,16,21,2,' e_ID=1 --> ',6,7,8,16,21,2,' LIKE '%,1,%' ? FALSE e_ID=6 --> ',6,7,8,16,21,2,' LIKE '%,6,%' ? TRUE e_ID=21 --> ',6,7,8,16,21,2,' LIKE '%,21,%' ? TRUE e_ID=2 --> ',6,7,8,16,21,2,' LIKE '%,2,%' ? TRUE e_ID=3 --> ',6,7,8,16,21,2,' LIKE '%,3,%' ? FALSE etc. 

这一个在oracle中..这里string连接是由wm_concat完成的

 select * from table where e_ID in (Select wm_concat(city) from locations where e_Id=?) 

是的,我同意raheel shan ..为了把这个“在”条款,我们需要把该列成行下面的代码一个做这项工作。

 select * from table where to_char(e_ID) in ( select substr(city,instr(city,',',1,rownum)+1,instr(city,',',1,rownum+1)-instr(city,',',1,rownum)-1) from ( select ','||WM_CONCAT(city)||',' city,length(WM_CONCAT(city))-length(replace(WM_CONCAT(city),','))+1 CNT from locations where e_Id=? ) TST ,ALL_OBJECTS OBJ where TST.CNT>=rownum ) ; 

你应该使用

FIND_IN_SET以逗号分隔值的stringforms返回值的位置

 mysql> SELECT FIND_IN_SET('b','a,b,c,d'); -> 2 

不知道这是你想要完成的。 使用MySQL,可以连接组GROUP_CONCAT中的值

你可以尝试这样的事情:

 select * from table where e_ID in (Select GROUP_CONCAT(city SEPARATOR ',') from locations where e_Id=?) 

IN采取行,所以采取逗号分隔列search将不会做你想要的,但如果你提供这样的数据('1','2','3')这将工作,但你不能保存这样的数据在你的领域无论你在列中插入什么,它将整个事情作为一个string。

您需要“分拆”城市列值。 这将是:

 SELECT * FROM table WHERE e_ID IN (SELECT TO_NUMBER( SPLIT_STR(city /*string*/ , ',' /*delimiter*/ , 1 /*start_position*/ ) ) FROM locations); 

你可以在这里阅读更多关于MySQL split_str函数: http ://blog.fedecarg.com/2009/02/22/mysql-split-string-function/

另外,我在这里使用了Oracle的TO_NUMBER函数。 请用适当的MySQL函数replace它。

你可以像这样dynamic地创build一个准备好的语句

 set @sql = concat('select * from city where city_id in (', (select cities from location where location_id = 3), ')'); prepare in_stmt from @sql; execute in_stmt; deallocate prepare in_stmt;