MySQL sorgusu, virgülle ayrılmış bir dizede değerleri bulma


93

Ben bir saha var COLORS (varchar(50))bir benim tabloda SHIRTSbir virgül gibi dize ayrılmış 1,2,5,12,15,. Mevcut renkleri temsil eden her sayı.

select * from shirts where colors like '%1%'Tüm kırmızı gömlekleri (renk = 1) almak için sorgu çalıştırırken, rengi gri (= 12) ve turuncu (= 15) olan gömlekleri de alıyorum.

Sorguyu, SADECE 1. rengi seçecek ve 1 rakamını içeren tüm renkleri seçmeyecek şekilde nasıl yeniden yazmalıyım?


6
Bunu normal ifadeyle yapabilirsiniz, sanırım, ancak çok daha iyi bir çözüm, gömlek renklerini ayrı bir tabloya (renklere) ayırmak ve bunları bağlamak için renk / gömlek kimliklerini kullanarak bir birleştirme tablosu (gömlek renkleri) kullanmak olacaktır.
ceejayoz

6 cevaba inanamıyorum hiçbiri MySQL'in SET veri tipinden
bahsetmedi

Yanıtlar:


190

Klasik yol, sola ve sağa virgül eklemektir:

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

Ancak find_in_set ayrıca çalışır:

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

Find_in_set'i denedim ama girdiğim renk değeri ne olursa olsun aynı sonucu döndürüyor ... Herhangi bir öneriniz var mı?
bikey77

@ bikey77: Belki sorun budur, dokümantasyon şunu söylüyor: İlk bağımsız değişken virgül (",") karakteri içeriyorsa bu işlev düzgün çalışmıyor.
Andomar

Yanlışım, aynı kukla değerlerden kaynaklanan mantıksal bir hataydı. İyi çalışıyor. Teşekkürler!
bikey77

@Andomar Cevabınızı bulmadan önce IN ile mücadele ediyordum ama sizinki bir cazibe gibi çalışıyor ... Çok teşekkür ederim ..
PHP Mentor

3
Find_in_set dizini kullanmadığı için performans etkisi var
Kamran Shahid



11

Bu kesinlikle işe yarayacak ve aslında denedim:

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)

Bir şans ver !!!


Hey @rolandomysqldba, sorgunuzu test ediyorum ve iyi çalışıyor ancak bazı değişiklikler yapmam gerekiyor. Sütunda renk değeri 1,2 olan tüm gömlekleri almak istersem diyelim.
Ahsan Saeed

6

Renk grubu az çok sabitse, en verimli ve aynı zamanda en okunabilir yol, uygulamanızda dize sabitlerini kullanmak ve ardından sorgularınızda MySQL SETtürünü kullanmaktır FIND_IN_SET('red',colors). Kullanırken SETile tipi FIND_IN_SET MySQL tüm değerleri depolamak için bir tam sayıyı kullanır ve ikili kullanan "and"virgülle ayrılmış dize tarama yolu daha verimlidir değerlerin varlığını kontrol etmek için işlem.

Olarak SET('red','blue','green'), 'red'dahili olarak depolanır olacağını 1, 'blue'dahili şekilde olacağını 2ve 'green'dahili şekilde olacaktır 4. Değeri 'red,blue'olarak saklanır, 3( 1|2) ve 'red,green'şekilde 5( 1|4).



3

Üç tablonuz olacak şekilde veritabanı şemanızı gerçekten düzeltmelisiniz:

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

Ardından kırmızı olan tüm gömlekleri bulmak istiyorsanız, aşağıdaki gibi bir sorgu yaparsınız:

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: Bu yalnızca OP'nin veritabanı şeması üzerinde düzenleme haklarına sahip olduğunu varsayarsanız geçerlidir; veritabanını yeniden tasarlama, verileri taşıma ve tüm istemcileri yeniden düzenleme zamanı vardır; ve bu sorgu için karmaşıklığın azaltılmasının, uygulamanın geri kalanında karmaşıklıktaki artıştan daha ağır basıyor.
Andomar

1
@Andomar, sonra tekrar satır geri getirme için boyut kısıtlamalarıyla karşılaşacak ve "kayıtları" kırpılacak, işte o zaman gerçek eğlence başlayacak!
Blindy

3
@Blindy: Bir noktayı kaçırıyorsun; En iyi çözüme sahip olduğunu iddia etmiyorum, sadece herkesin ortamını beğenisine göre yeniden tasarlama özgürlüğüne sahip olmadığını
tartışmıyorum

@Andomar'a katılıyorum
Adam B

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

Benim için çalışıyor


0

1. MySQL için:

SELECT FIND_IN_SET(5, columnname) AS result 
FROM table

2. Postgres SQL için:

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

Misal

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

0

Bunu aşağıdaki işlevi takip ederek başarabilirsiniz.

İşlev oluşturmak için aşağıdaki sorguyu çalıştırın.

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)        
);

Ve bu işlevi şöyle adlandırın

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

-7

Tüm cevaplar gerçekten doğru değil, şunu deneyin:

select * from shirts where 1 IN (colors);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.