Kueri MySQL menemukan nilai dalam string yang dipisahkan koma

93

Saya memiliki bidang COLORS (varchar(50))dalam tabel saya SHIRTSyang berisi string yang dipisahkan koma seperti 1,2,5,12,15,. Setiap angka mewakili warna yang tersedia.

Saat menjalankan query select * from shirts where colors like '%1%'untuk mendapatkan semua kaos merah (color = 1), saya juga mendapatkan kaos yang warnanya abu-abu (= 12) dan oranye (= 15).

Bagaimana saya harus menulis ulang query sehingga yang dipilih HANYA warna 1 dan tidak semua warna mengandung angka 1?

sepeda
sumber
6
Anda dapat melakukan ini melalui regex, saya kira, tetapi solusi yang jauh lebih baik adalah memecah warna kemeja menjadi tabel terpisah (warna) dan menggunakan tabel gabungan (shirt_colors) menggunakan id warna / kemeja untuk menghubungkannya.
ceejayoz
Saya tidak percaya dengan 6 jawaban tidak satupun dari mereka menyebutkan tipe data SET MySQL ..
ColinM

Jawaban:

190

Cara klasik adalah menambahkan koma di kiri dan kanan:

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

Tetapi find_in_set juga berfungsi:

select * from shirts where find_in_set('1',colors) <> 0
Andomar
sumber
Saya mencoba find_in_set tetapi mengembalikan hasil yang sama tidak peduli nilai warna yang saya masukkan ... Ada saran?
bikey77
@ bikey77: Mungkin ini masalahnya, dokumentasinya mengatakan: Fungsi ini tidak berfungsi dengan baik jika argumen pertama berisi karakter koma (",").
Andomar
Salah saya, itu adalah kesalahan logis karena nilai dummy yang sama. Ini bekerja dengan baik. Terima kasih!
bikey77
@Andomar Sebelum saya menemukan jawaban Anda, saya berjuang dengan IN tetapi milik Anda bekerja seperti pesona ... Terima kasih banyak ..
PHP Mentor
3
Ini memiliki dampak kinerja karena Find_in_set tidak menggunakan indeks
Kamran Shahid
31

FIND_IN_SET adalah teman Anda dalam kasus ini

select * from shirts where FIND_IN_SET(1,colors) 
Shakti Singh
sumber
4
find_in_set terlalu lambat untuk tabel besar
Jeff_Alieffson
24

Lihatlah fungsi FIND_IN_SET untuk MySQL.

SELECT * 
    FROM shirts 
    WHERE FIND_IN_SET('1',colors) > 0
Joe Stefanelli
sumber
1
Hati-hati: find in set tidak menggunakan indeks pada tabel.
edigu
11

Ini pasti berhasil, dan saya benar-benar mencobanya:

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)

Cobalah !!!

RolandoMySQLDBA
sumber
Hai @rolandomysqldba, saya menguji kueri Anda dan berfungsi dengan baik tetapi saya perlu membuat beberapa perubahan di dalamnya. Katakanlah jika saya ingin mendapatkan semua kaos dengan nilai warna 1,2 di kolom.
Ahsan Saeed
6

Jika kumpulan warna kurang lebih tetap, cara yang paling efisien dan juga paling mudah dibaca adalah dengan menggunakan konstanta string di aplikasi Anda dan kemudian menggunakan SETtipe MySQL dengan FIND_IN_SET('red',colors)dalam kueri Anda. Saat menggunakan SETtipe dengan FIND_IN_SET , MySQL menggunakan satu integer untuk menyimpan semua nilai dan menggunakan "and"operasi biner untuk memeriksa keberadaan nilai yang jauh lebih efisien daripada memindai string yang dipisahkan koma.

Dalam SET('red','blue','green'), 'red'akan disimpan secara internal sebagai 1, 'blue'akan disimpan secara internal sebagai 2dan 'green'akan disimpan secara internal sebagai 4. Nilainya 'red,blue'akan disimpan sebagai 3( 1|2) dan 'red,green'sebagai 5( 1|4).

ColinM
sumber
3

Jika Anda menggunakan MySQL, ada metode REGEXP yang dapat Anda gunakan ...

http://dev.mysql.com/doc/refman/5.1/en/regexp.html#operator_regexp

Jadi Anda akan menggunakan:

SELECT * FROM `shirts` WHERE `colors` REGEXP '\b1\b'
KOGI
sumber
Tidak bisa memahami yang ini, meskipun saya cukup yakin itu salah saya. Terima kasih teman sejuta.
bikey77
3

Anda harus benar-benar memperbaiki skema database Anda sehingga Anda memiliki tiga tabel:

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

Kemudian jika Anda ingin menemukan semua kemeja yang berwarna merah, Anda akan melakukan kueri seperti:

SELECT *
FROM shirt, color
WHERE color.color_name = 'red'
  AND shirt.shirt_id = shirtcolor.shirt_id
  AND color.color_id = shirtcolor.color_id
CanSpice
sumber
8
@ Blindy: Itu hanya benar jika Anda menganggap OP memiliki hak edit pada skema database; memiliki waktu untuk mendesain ulang database, memigrasi data, dan memfaktor ulang semua klien; dan bahwa pengurangan kompleksitas untuk kueri ini melebihi peningkatan kompleksitas di bagian aplikasi lainnya.
Andomar
1
@Andomar, sekali lagi ketika dia akan mengalami batasan ukuran untuk pengambilan baris dan "catatan" nya akan terpotong, saat itulah kesenangan yang sebenarnya akan dimulai!
Blindy
3
@ Blindy: Anda kehilangan intinya; Saya tidak berargumen bahwa dia memiliki solusi terbaik, hanya saja tidak semua orang memiliki kebebasan untuk mendesain ulang lingkungannya sesuai dengan keinginannya
Andomar
Saya setuju dengan @Andomar
Adam B
3
select * from shirts where find_in_set('1',colors) <> 0

Bekerja untuk saya

Deepak Bhatta
sumber
0

1. Untuk MySQL:

SELECT FIND_IN_SET(5, columnname) AS result 
FROM table

2. Untuk Postgres SQL:

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

Contoh

select * 
from customer f
where '11' = ANY (string_to_array(customerids, ','))
Saranga kapilarathna
sumber
0

Anda dapat mencapai ini dengan mengikuti fungsi.

Jalankan kueri berikut untuk membuat fungsi.

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

Dan panggil fungsi ini seperti ini

msyql> select TOTAL_OCCURANCE('A,B,C,A,D,X,B,AB', 'A');
Delickate
sumber
-7

Semua jawaban tidak benar-benar benar, coba ini:

select * from shirts where 1 IN (colors);
Mundur
sumber