MySQL LIKE IN ()?

273

Kueri saya saat ini terlihat seperti ini:

SELECT * FROM fiberbox f WHERE f.fiberBox LIKE '%1740 %' OR f.fiberBox LIKE '%1938 %' OR f.fiberBox LIKE '%1940 %'

Saya melakukan beberapa melihat-lihat dan tidak dapat menemukan sesuatu yang mirip dengan LIKE IN () - Saya membayangkannya bekerja seperti ini:

SELECT * FROM fiberbox f WHERE f.fiberbox LIKE IN('%140 %', '%1938 %', '%1940 %')

Ada ide? Apakah saya hanya memikirkan masalah dengan cara yang salah - beberapa perintah tidak jelas yang belum pernah saya lihat.

MySQL 5.0.77-komunitas-log

Michael Wales
sumber
1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl
2
FIND_IN_SET tidak menerima wildcard seperti%
Sebastián Grignoli

Jawaban:

454

Sebuah regexp mungkin lebih efisien, tetapi Anda harus patokan itu untuk memastikan, misalnya

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
Paul Dixon
sumber
2
Saya suka jawaban ini - cepat, sederhana, mendapat semua "opsi" dalam satu baris seperti yang saya inginkan (mudah diedit). Pada hasil kecil yang saya targetkan, tidak ada penurunan kinerja sama sekali.
Michael Wales
51
Lebih dari 1 juta baris di meja saya. REGEX sekitar 0,0009 dan LIKE sekitar 0,0005. Jika lebih dari 5 REGEX, sekitar 0,0012 ...
David Bélanger
10
Saya memiliki masalah di mana REGEXPsangat lambat, tetapi saya membutuhkan fleksibilitas REGEXP untuk mempersempit hasil yang saya set lebih jauh dari yang LIKEdapat disediakan. Saya datang dengan solusi hybrid di mana saya menggunakan keduanya LIKEdan REGEXP; meskipun REGEXPporsinya cukup untuk memberi saya hasil yang benar, menggunakan LIKEMySQL juga memungkinkan untuk mengurangi hasil yang ditetapkan sebelum harus menggunakan REGEXPkriteria yang lebih lambat .
mpen
1
Untuk mendapatkan nilai regexp dari kolom:(select group_concat(myColumn separator '|') from..)
daVe
5
Menambah data kinerja. Di MySql 5.5 dalam sebuah tabel dengan baris 229M, 1 istilah tersisa berlabuh 3 pencarian char: REGEXP: 16s, LIKE: 8.5s; 2 istilah: REGEXP: 22.1s, SEPERTI: 9.69; '^ (hemoglobin | hematr? ocrit). *' vs 3 istilah seperti: REGEXP: 36.3, SUKA: 9.59.
Jesse Clark
181

Jawaban Paul Dixon sangat membantu saya. Untuk menambah ini, berikut adalah beberapa hal yang saya amati bagi mereka yang tertarik menggunakan REGEXP:

Untuk Menyelesaikan beberapa filter LIKE dengan Wildcard:

 SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                           OR field LIKE '%1938 %'
                           OR field LIKE '%1940 %';  

Gunakan Alternatif REGEXP:

 SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |1940 ';

Nilai dalam kutipan REGEXP dan di antara | (OR) operator diperlakukan sebagai wildcard. Biasanya, REGEXP akan membutuhkan ekspresi wildcard seperti (. *) 1740 (. *) Untuk bekerja sebagai% 1740%.

Jika Anda memerlukan kontrol lebih besar atas penempatan wildcard, gunakan beberapa varian ini:

Untuk Menyelesaikan SEPERTI dengan Penempatan Wildcard Terkendali:

SELECT * FROM fiberbox WHERE field LIKE '1740 %'
                          OR field LIKE '%1938 '
                          OR field LIKE '%1940 % test';  

Menggunakan:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Menempatkan ^ di depan nilai mengindikasikan awal baris.

  • Menempatkan $ setelah nilai menunjukkan ujung baris.

  • Menempatkan (. *) Berlaku seperti% wildcard.

  • . menunjukkan karakter tunggal, kecuali jeda baris. Menempatkan. inside () dengan * (. *) menambahkan pola berulang yang menunjukkan sejumlah karakter hingga akhir baris.

Ada cara yang lebih efisien untuk mempersempit pertandingan tertentu, tetapi itu membutuhkan lebih banyak ulasan tentang Ekspresi Reguler. CATATAN: Tidak semua pola regex tampaknya berfungsi dalam pernyataan MySQL. Anda perlu menguji pola Anda dan melihat apa yang berhasil.

Akhirnya, Untuk Menyelesaikan Beberapa LIKE dan NOT LIKE filter:

SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                          OR field LIKE '%1938 %'
                          OR field NOT LIKE '%1940 %'
                          OR field NOT LIKE 'test %'
                          OR field = '9999';

Gunakan Alternatif REGEXP:

SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |^9999$'
                          OR field NOT REGEXP '1940 |^test ';

ATAU Alternatif Campuran:

SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 '
                          OR field NOT REGEXP '1940 |^test '
                          OR field NOT LIKE 'test %'
                          OR field = '9999';

Perhatikan saya memisahkan TIDAK diatur dalam filter WHERE terpisah. Saya bereksperimen dengan menggunakan pola negating, pola berwawasan ke depan, dan sebagainya. Namun, ekspresi ini tampaknya tidak membuahkan hasil yang diinginkan. Pada contoh pertama di atas, saya menggunakan ^ 9999 $ untuk menunjukkan kecocokan persis. Ini memungkinkan Anda untuk menambahkan kecocokan spesifik dengan kecocokan wildcard dalam ekspresi yang sama. Namun, Anda juga dapat mencampur jenis pernyataan ini seperti yang Anda lihat pada contoh kedua yang tercantum.

Mengenai kinerja, saya menjalankan beberapa tes kecil terhadap tabel yang ada dan tidak menemukan perbedaan antara variasi saya. Namun, saya membayangkan kinerja bisa menjadi masalah dengan database yang lebih besar, bidang yang lebih besar, jumlah catatan yang lebih besar, dan filter yang lebih kompleks.

Seperti biasa, gunakan logika di atas karena itu masuk akal.

Jika Anda ingin mempelajari lebih lanjut tentang ekspresi reguler, saya sarankan www.regular-expressions.info sebagai situs referensi yang bagus.

David Carroll
sumber
Perlu diingat bahwa bidang dengan nilai NULL tidak akan cocok dengan REGEXP. Anda dapat menggunakan IFNULL untuk menyelesaikan masalah ini. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
@DanyMarcoux Bagaimana jika saya ingin menggunakan (. *) Tetapi harus bertindak seperti FIELDNAME LIKE '%%', bagaimana menggunakannya dengan regexp, sehingga ketika sebuah string kosong dilewatkan. itu harus mengambil semua catatan ..
shzyincu
Field WHERE NOT LIKE '% 1940%' ATAU field NOT LIKE 'test%' akan selalu mengembalikan semua baris. Itu mungkin berkontribusi untuk tidak menghasilkan hasil yang diinginkan yang Anda sebutkan?
Herbert Van-Vliet
14

Anda dapat membuat tampilan inline atau tabel sementara, mengisinya dengan nilai Anda dan mengeluarkan ini:

SELECT  *
FROM    fiberbox f
JOIN    (
        SELECT '%1740%' AS cond
        UNION ALL
        SELECT '%1938%' AS cond
        UNION ALL
        SELECT '%1940%' AS cond
        ) с
ON      f.fiberBox LIKE cond

Akan tetapi, ini bisa mengembalikan Anda beberapa baris untuk fiberboxsesuatu yang mirip '1740, 1938', jadi kueri ini lebih cocok untuk Anda:

SELECT  *
FROM    fiberbox f
WHERE   EXISTS
        (
        SELECT  1
        FROM    (
                SELECT '%1740%' AS cond
                UNION ALL
                SELECT '%1938%' AS cond
                UNION ALL
                SELECT '%1940%' AS cond
                ) с
        WHERE   f.fiberbox LIKE cond
        )
Quassnoi
sumber
13

Cara Regexp dengan daftar nilai

SELECT * FROM table WHERE field regexp concat_ws("|",
"111",
"222",
"333");
pengguna136379
sumber
7

Maaf, tidak ada operasi yang mirip dengan LIKE INdi mysql.

Jika Anda ingin menggunakan operator LIKE tanpa bergabung, Anda harus melakukannya dengan cara ini:

(field LIKE value OR field LIKE value OR field LIKE value)

Anda tahu, MySQL tidak akan mengoptimalkan permintaan itu, FYI.

gahooa
sumber
4

Catat saja kepada siapa pun yang mencoba REGEXP untuk menggunakan fungsionalitas "LIKE IN".

IN memungkinkan Anda melakukan:

field IN (
'val1',
'val2',
'val3'
)

Di REGEXP ini tidak akan berfungsi

REGEXP '
val1$|
val2$|
val3$
'

Itu harus dalam satu baris seperti ini:

REGEXP 'val1$|val2$|val3$'
Shaakir
sumber
3

Operan balik

'a,b,c' like '%'||field||'%'
Ed Heal
sumber
2
ketika Anda memiliki beberapa bidang secara eksplisit akan sama dengan sesuatu misalnya. enum untuk lulusan 'a', 'b', 'c' tetapi tidak ab, ac atau bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en hanya a atau b yang melakukan metode ini dengan membalik oprand select * from, x where 'a,c' like concat('%',en,'%')dapat lebih aman dalam SQL Injunction tidak perlu lepas dari karakter seperti $ ^ dll.
Ini BUKAN setara dan TIDAK AKAN BEKERJA untuk kasus-kasus umum. Jika Anda tahu itu fieldhanya bisa tepat a, batau cAnda harus menggunakannya field IN ('a', 'b', 'c'). Tetapi dalam kasus umum, ini TIDAK PERNAH bisa menggantikan field LIKE '%a%' OR field LIKE '%b%' OR ...karena bidang itu sendiri bisa menjadi sesuatu seperti magicyang akan membuat 'magic' LIKE '%a%'benar tetapi ekspresi 'a,b,c' LIKE '%magic%'salah.
ADTC
2

Ini benar:

SELECT * FROM table WHERE field regexp concat_ws("|",(
"111",
"222",
"333"
));
Edmhs
sumber
2

Sedikit tip:

Saya lebih suka menggunakan varian RLIKE (perintah yang persis sama dengan REGEXP ) karena kedengarannya lebih mirip bahasa alami, dan lebih pendek; baik, hanya 1 char.

Awalan "R" adalah untuk Reg. Exp., Tentu saja.

Raúl Moreno
sumber
0

Anda bisa mendapatkan hasil yang diinginkan dengan bantuan Ekspresi Reguler .

SELECT fiberbox from fiberbox where fiberbox REGEXP '[1740|1938|1940]';

Kami dapat menguji permintaan di atas, silakan klik SQL biola

SELECT fiberbox from fiberbox where fiberbox REGEXP '[174019381940]';

Kami dapat menguji permintaan di atas, silakan klik SQL biola

ZIJ
sumber
1
Ini adalah ekspresi reguler yang salah. [...]adalah set karakter , yang berarti bahwa salah satu karakter dalam set cukup untuk dilihat sebagai pasangan. Jadi setiap nilai dengan angka ' 0, 1, 3, 4, 7, 8, 9atau |karakter pipa akan cocok ini.
Martijn Pieters