MySQL"IN"子句中的逗号分隔值

Sas*_*ant 25 php mysql sql

我在我的一个表中有一个列,其中存储了多个由逗号分隔的ID.有没有一种方法可以在查询的"IN"子句中使用此列的值.

列(city)的值类似于6,7,8,16,21,2

我需要使用as

select * from table where e_ID in (Select city from locations where e_Id=?)
Run Code Online (Sandbox Code Playgroud)

我对Crozin的回​​答感到满意,但我对建议,观点和选择持开放态度.

随意分享您的观点.

Bil*_*win 29

在@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 = ?
Run Code Online (Sandbox Code Playgroud)

这是众所周知的非常表现不佳,因为它做表扫描,评估FIND_IN_SET()函数每一行的组合tablelocations.它无法使用索引,也无法改进它.

我知道你说你正在努力充分利用糟糕的数据库设计,但你必须明白这是多么糟糕.

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

LIKE@fthiella给出的解决方案在性能方面存在类似问题.它无法编入索引.

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

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

CREATE TABLE location2city (
 location INT,
 city INT,
 PRIMARY KEY (location, city)
); 
Run Code Online (Sandbox Code Playgroud)

假设你有一个所有可能城市的查找表(不仅仅是那些提到的那些城市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;
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM location2city l
JOIN table t ON t.e_ID = l.city
WHERE l.e_ID = ?;
Run Code Online (Sandbox Code Playgroud)

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


Cro*_*zin 25

从MySQL的角度来看,你不是存储用逗号分隔的多个id - 你存储的文本值与"Hello World"或"I like cakes!"完全相同. - 即它没有任何意义.

您需要做的是创建一个将数据库中的两个对象链接在一起的分隔表.阅读有关基于SQL的数据库中的多对多一对多(取决于您的要求)关系的更多信息.


Jer*_*yth 24

Rather than use IN on your query, use FIND_IN_SET (docs):

SELECT * FROM table 
WHERE 0 < FIND_IN_SET(e_ID, (
             SELECT city FROM locations WHERE e_ID=?))
Run Code Online (Sandbox Code Playgroud)

The usual caveats about first form normalization apply (the database shouldn't store multiple values in a single column), but if you're stuck with it, then the above statement should help.

  • 性能相对较差,因为`FIND_IN_SET`不能使用任何索引.如果你担心性能(并且有权这样做),你真的需要使用1nf将`locations` .city`列拆分成另一个表,然后你可以使用索引来帮助你提高性能. (2认同)

fth*_*lla 21

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

Select *
from table
where
  CONCAT(',', (Select city from locations where e_Id=?), ',')
  LIKE
  CONCAT('%,', e_ID, ',%')
Run Code Online (Sandbox Code Playgroud)

但你必须确保它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.
Run Code Online (Sandbox Code Playgroud)


GKV*_*GKV 7

这个用于oracle ..其中字符串连接由wm_concat完成

select * from table where e_ID in (Select wm_concat(city) from locations where e_Id=?)
Run Code Online (Sandbox Code Playgroud)

是的我同意raheel shan ..为了把这个"in"子句放在我们需要将该列放到代码下面的行中,就可以完成这项工作.

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
    ) ;
Run Code Online (Sandbox Code Playgroud)


Rin*_*ler 6

你应该使用

FIND_IN_SET以逗号分隔值的字符串形式返回值的位置

mysql> SELECT FIND_IN_SET('b','a,b,c,d');
    -> 2
Run Code Online (Sandbox Code Playgroud)


Sub*_*Red 6

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

你可以尝试这样的事情:

select * from table where e_ID in (Select GROUP_CONCAT(city SEPARATOR ',') from locations where e_Id=?)
Run Code Online (Sandbox Code Playgroud)


Rac*_*cha 6

您需要"拆分"城市列值.它会像:

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

您可以在此处阅读有关MySQL split_str函数的更多信息:http://blog.fedecarg.com/2009/02/22/mysql-split-string-function/

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


Muh*_*eel 5

IN需要行,因此使用逗号分隔列进行搜索将无法执行您想要的操作,但如果您提供此类数据('1','2','3'),这将有效,但您无法在您的字段中保存此类数据无论你在列中插入什么,它都会将整个事物作为一个字符串.