MySQL查询以逗号分隔的字符串查找值


90

我的COLORS (varchar(50))表格SHIRTS中有一个字段,其中包含逗号分隔的字符串,例如1,2,5,12,15,。每个数字代表可用的颜色。

在运行查询select * from shirts where colors like '%1%'以获取所有红色衬衫(颜色= 1)时,我还获得了颜色为灰色(= 12)和橙色(= 15)的衬衫。

我应该如何重写查询,以便仅选择颜色1而不是选择所有包含数字1的颜色?


6
我想您可以通过正则表达式来做到这一点,但是更好的解决方案是将衬衫颜色分成一个单独的表(颜色),并使用一个连接表(shirt_colors)使用颜色/衬衫的ID进行链接。
ceejayoz

我不能相信与6个答案没有人提及MySQL的一组数据类型..
ColinM

Answers:


185

经典方法是在左右添加逗号:

select * from shirts where CONCAT(',', colors, ',') like '%,1,%'

但是find_in_set也可以:

select * from shirts where find_in_set('1',colors) <> 0

我尝试过find_in_set,但是无论我输入的颜色值如何,它都会返回相同的结果...有什么建议吗?
bikey77 2011年

@ bikey77:也许是问题所在,文档说:如果第一个参数包含逗号(“,”)字符,则此功能无法正常工作。
2011年

我的错,由于相同的虚拟值,这是一个逻辑错误。它工作正常。谢谢!
bikey77 2011年

@Andomar在我找到答案之前,我并没有在IN方面苦苦挣扎,但您的工作却像魅力一样……非常感谢..
PHP Mentor 2012年

2
由于未使用Find_in_set索引,因此会对性能产生影响-Kamran
Shahid



11

这肯定会起作用,而我实际上已经尝试了:

lwdba@localhost (DB test) :: DROP TABLE IF EXISTS shirts;
Query OK, 0 rows affected (0.08 sec)

lwdba@localhost (DB test) :: CREATE TABLE shirts
    -> (<BR>
    -> id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    -> ticketnumber INT,
    -> colors VARCHAR(30)
    -> );<BR>
Query OK, 0 rows affected (0.19 sec)

lwdba@localhost (DB test) :: INSERT INTO shirts (ticketnumber,colors) VALUES
    -> (32423,'1,2,5,12,15'),
    -> (32424,'1,5,12,15,30'),
    -> (32425,'2,5,11,15,28'),
    -> (32426,'1,2,7,12,15'),
    -> (32427,'2,4,8,12,15');
Query OK, 5 rows affected (0.06 sec)
Records: 5  Duplicates: 0  Warnings: 0

lwdba@localhost (DB test) :: SELECT * FROM shirts WHERE LOCATE(CONCAT(',', 1 ,','),CONCAT(',',colors,',')) > 0;
+----+--------------+--------------+
| id | ticketnumber | colors       |
+----+--------------+--------------+
|  1 |        32423 | 1,2,5,12,15  |
|  2 |        32424 | 1,5,12,15,30 |
|  4 |        32426 | 1,2,7,12,15  |
+----+--------------+--------------+
3 rows in set (0.00 sec)

试试看 !!!


嘿@rolandomysqldba,我测试了您的查询,它可以正常运行,但是我需要对其进行一些更改。假设我要在列中获取所有颜色值为1,2的衬衫。
Ahsan Saeed

6

如果颜色的设置或多或少是固定的,那么最有效,也最易读的方法是在应用中使用字符串常量,然后在查询中使用MySQL的SET类型FIND_IN_SET('red',colors)。当将SET类型与FIND_IN_SET一起使用时,MySQL使用一个整数来存储所有值,并使用二进制"and"操作来检查值的存在,这比扫描逗号分隔的字符串更有效。

在中SET('red','blue','green')'red'将在内部存储为1'blue'在内部将存储为,2并且'green'将在内部存储为4。该值'red,blue'将被存储为31|2)和'red,green'作为51|4)。



3

您实际上应该修复数据库架构,以便拥有三个表:

shirt: shirt_id, shirt_name
color: color_id, color_name
shirtcolor: shirt_id, color_id

然后,如果您要查找所有红色的衬衫,则可以执行以下查询:

SELECT *
FROM shirt, color
WHERE color.color_name = 'red'
  AND shirt.shirt_id = shirtcolor.shirt_id
  AND color.color_id = shirtcolor.color_id

8
@Blindy:仅当您假设OP对数据库模式具有编辑权限时,这才是正确的;有时间重新设计数据库,迁移数据并重构所有客户端;并且此查询的复杂性降低超过了其余应用程序的复杂性增长。
2011年

1
@Andomar,然后当他再次遇到行检索的大小限制并且他的“记录”将被裁剪时,这才是真正的乐趣!
布林迪

3
@Blindy:您错过了重点;我并不认为他有最好的解决方案,只是不是每个人都可以自由地他的环境重新设计对他的胃口
Andomar

我同意@Andomar
Adam B


0

1.对于MySQL:

SELECT FIND_IN_SET(5, columnname) AS result 
FROM table

2.对于Postgres SQL:

SELECT * 
FROM TABLENAME f
WHERE 'searchvalue' = ANY (string_to_array(COLUMNNAME, ','))

select * 
from customer f
where '11' = ANY (string_to_array(customerids, ','))

0

您可以通过以下功能来实现。

运行以下查询以创建函数。

DELIMITER ||
CREATE FUNCTION `TOTAL_OCCURANCE`(`commastring` TEXT, `findme`     VARCHAR(255)) RETURNS int(11)
NO SQL
-- SANI: First param is for comma separated string and 2nd for string to find.
return ROUND (   
    (
        LENGTH(commastring)
        - LENGTH( REPLACE ( commastring, findme, "") ) 
    ) / LENGTH(findme)        
);

并像这样调用此函数

msyql> select TOTAL_OCCURANCE('A,B,C,A,D,X,B,AB', 'A');

-7

并非所有答案都正确,请尝试以下操作:

select * from shirts where 1 IN (colors);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.