쉼표로 구분 된 문자열에서 값을 찾는 MySQL 쿼리


92

COLORS (varchar(50))내 테이블 SHIRTS에와 같은 쉼표로 구분 된 문자열이 포함 된 필드 가 있습니다 1,2,5,12,15,. 사용 가능한 색상을 나타내는 각 숫자.

select * from shirts where colors like '%1%'모든 빨간색 셔츠 (color = 1)를 가져 오는 쿼리 를 실행할 때 색상이 회색 (= 12)과 주황색 (= 15) 인 셔츠도 가져옵니다.

숫자 1을 포함하는 모든 색상이 아닌 색상 1 만 선택하도록 쿼리를 어떻게 다시 작성해야합니까?


6
정규식을 통해이 작업을 수행 할 수 있지만 훨씬 더 나은 해결책은 셔츠 색상을 별도의 테이블 (색상)로 나누고 색상 / 셔츠의 ID를 사용하여 조인 테이블 (shirt_colors)을 사용하여 연결하는 것입니다.
ceejayoz

나는 6 개의 답변으로 믿을 수 없다. 그들 중 아무도 MySQL의 SET 데이터 유형을 언급 하지 않았다 .
ColinM

답변:


189

고전적인 방법은 왼쪽과 오른쪽에 쉼표를 추가하는 것입니다.

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

@ bikey77 : 아마도 이것이 문제 일 수 있습니다. 문서에 이렇게 나와 있습니다. 첫 번째 인수에 쉼표 (“,”) 문자가 포함되어 있으면이 함수가 제대로 작동하지 않습니다.
Andomar

내 잘못은 동일한 더미 값으로 인한 논리적 실수였습니다. 잘 작동합니다. 감사!
bikey77

@Andomar 내가 너무 .. 감사 ... 내가 IN 고민을 받았 느니라 그러나 당신이 마법처럼 작품 답을 발견하기 전에
PHP 멘토

3
Find_in_set이 인덱스를 사용하지 않기 때문에 성능에 영향을 미칩니다
Kamran Shahid


24

MySQL 용 FIND_IN_SET 함수를 살펴보십시오 .

SELECT * 
    FROM shirts 
    WHERE FIND_IN_SET('1',colors) > 0

1
주의 : 세트에서 찾기는 테이블의 인덱스를 사용하지 않습니다.
edigu

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)하는 것입니다. FIND_IN_SETSET 과 함께 유형을 사용할 때 MySQL은 하나의 정수를 사용하여 모든 값을 저장하고 이진 연산을 사용 하여 쉼표로 구분 된 문자열을 스캔하는 것보다 훨씬 효율적인 값의 존재 여부를 확인합니다."and"

에서 SET('red','blue','green'), 'red'내부적으로 저장됩니다 1, 'blue'로 내부에 저장 될 수 2'green'같이 내부적으로 저장됩니다 4. 값이 'red,blue'저장된다 3( 1|2)와 'red,green'같이 5( 1|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에 데이터베이스 스키마에 대한 편집 권한이 있다고 가정하는 경우에만 해당됩니다. 데이터베이스를 재 설계하고 데이터를 마이그레이션하고 모든 클라이언트를 리팩토링 할 시간이 있습니다. 이 쿼리에 대한 복잡성 감소가 나머지 애플리케이션의 복잡성 증가보다 중요합니다.
Andomar

1
@Andomar, 그가 행 검색을위한 크기 제한에 부딪 히고 그의 "레코드"가 잘릴 때 다시 진짜 재미가 시작됩니다!
Blindy

3
@Blindy : 요점을 놓치고 있습니다. 나는 모두가 자신의 취향에 맞게 자신의 환경을 재 설계 할 수있는 자유를 가지고 단지, 그가 최고의 솔루션을 제공한다고 주장하고 있지 않다
Andomar

나는 @Andomar에 동의
아담 B

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

나를 위해 작동


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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.