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?


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

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



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 !!!


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



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

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


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, ','))

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

-7

Semua jawaban tidak benar-benar benar, coba ini:

select * from shirts where 1 IN (colors);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.