2009-08-22 19 views
5

Basit kullanılmış bir alanı kullanarak MySQL'de kayıtları almaya çalışıyorum. Daha kesin olarak, kullanıcı bir ad (ad veya soyadı veya tam ad) girer ve sunucu eşleşen satırları döndürmelidir.MySQL içinde HAVING ve WHERE deyimi arasında 'VEYA' kullanma?

Şimdiye kadar ne yapıyorum gibi bir şey: şimdilik iyi çalışıyor

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

, ancak bir kullanıcı tamadı gönderdiğinde ki (tabii ki) çalışmaz. 'WHERE tipi koşullar' ve 'HAVING tipi koşullar' arasında bir OR eklemenin bir yolu var mı? Ben böyle bir şey yapabileceğini Bu şekilde:

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' OR 
    HAVING fullname LIKE '%user_submitted_data%' 

ben sadece orijinal dize bölmek biliyorum ama böyle 'de Gaule' ve bunun gibi şeyler olarak boşluk içeren adlara sahip uğraşmak zorunda beri bazı olumsuz etkisi vardır.

cevap

4

bir alt sorgu yapın: Kullanıcı ilk giriş girdiğinde, Şimdi

SELECT * FROM people 
WHERE 
    firstname LIKE '%user_submitted_data%' OR 
    lastname LIKE '%user_submitted_data%' 

:

John 
Smith 
John Smith 

Başlangıçtaki örnek sorgu geçerli:

SELECT [some fields] 
FROM 
    SELECT firstname, lastname, CONCAT(firstname, ' ', lastname) as fullname 
    FROM people) AS tmp 
WHERE firstname LIKE '%user_submitted_data%' 
OR lastname LIKE '%user_submitted_data%' 
OR fullname LIKE '%user_submitted_data%' 
+0

Teşekkürler, düzeltiyor. – Jimmy

1

en olası bazı girdileri düşünelim Bu sorgu, ilk adı 'John' olan tüm insanları seçecek; Ayrıca soyadı 'John' olan tüm insanları (örneğin, veritabanındaki tüm Johnsons'ları) seçecektir. Benzer şekilde, ikinci girdi ilk ismi 'Smith' olan tüm insanları seçecektir; Ayrıca soyadı 'Smith' (örneğin, Smithsons ve Smithers) içeren tüm kişileri de seçecektir. Çok uzak çok iyi; büyük/küçük harfe duyarlılık sorunları nedeniyle mükemmel değil (buradaki büyük küçük harf duyarlılıklarını görmezden geleceğim, ama muhtemelen göz ardı etmemelisiniz), ama sorun olmayacaktır.

Üçüncü girdi sadece ilk adı 'John Smith' olan kişileri seçecektir; Ayrıca soyadı “John Smith” i içeren kişileri de seçecektir. Bununla birlikte, bu kriterleri karşılayan çok az insanın olması muhtemeldir - John Smith adındaki insanlar sadece ilk adette John ve soyadıyla sadece Smith olacaktır. Aklında olan şey bu olması olası değildir.

Tabloda 'fullname' adında bir sütunun olup olmadığı net değil. Bunu yaparsanız, ilk ad ve soyadı yerine ayrı ayrı eşleştirmek yerine yalnızca bu sütuna karşı eşleşebilirsiniz. Eğer yapmazsanız, belki böyle bir sütun üretebilir ve sonra sorguyu buna karşı çalıştırabilirsiniz.

SELECT * 
    FROM (SELECT firstname || ' ' || lastname AS fullname, ... FROM people) AS t 
WHERE t.fullname LIKE '%user_submitted_data%' 

Bu, oldukça iyi çalışır. Bununla birlikte, eğer 'Charles De Gaulle' (ya da 'Charles de Gaulle') ya da 'Michael van den Berg' gibi isimlerden endişe ediyorsanız, birileri 'Charles Gaulle' ya da 'girerse eşleşme başarısız olur.' Michael Berg ', izin ver Michael Vandenberg. Kullanıcı girdisindeki herhangi bir boşluk karakterini de '%' simgesiyle değiştirmeniz gerekecektir. O zaman bile, sözlerin, kullanıcı tarafından verilen sırayla görünmesi gerektiği problemi ile karşı karşıya kalırsınız - ki bu önemli olmayabilir, ancak bunun fark edilmeyeceğine bilinçli olarak karar vermelisiniz. Örneğin, eğer girdi “Adam John Smith” ise, sorgu 'John Adam Smith'i yakalamaz; Eğer giriş 'Smith, John' ise, o zaman kimseyi almayacaktır (büyük ihtimalle).

Bunu yönetmek istiyorsanız, muhtemelen kullanıcının girişini belirtmeli ve ayrı sözcükleri aramalısınız.Bir sözcüğün alt dizesini soran birisine dikkat edin (örneğin, bir kişi bir isim sözcüğü olarak 'de' diye sorar) - Şu anda sorguların hiçbiri, kullanıcı giriş kelimelerinin değerlerde tam kelimelerle eşleşmesini sağlar (John vs Johnson), ve SQL standart LIKE operatörü ile bunu yapmak neredeyse imkansız.

+0

Derinlik bekçisi için teşekkürler. Bir nedenden dolayı, MySQL benim sistemime (OSX) büyük ölçüde duyarsız gibi geliyor, bu yüzden şimdiye kadar gayet iyi çalışıyor. Kelime siparişine gelince, LIKE operatörü içeriğe çok iyi uyuyor. Bir kullanıcı John Adam Smith'i aradığında çıkmaya (veya istemez) ihtiyacım yok. Arama örneği oldukça sınırlıdır. – Jimmy

0

bir alt sorguda bu sütunu tanımlarsanız Sen WHERE fıkrada hesaplanan bir sütun başvurabilirsiniz: Yaptığınız arama türü için, dürüst

SELECT p.* 
FROM (
    SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
    FROM people 
) p 
WHERE 
    p.firstname LIKE '%user_submitted_data%' OR 
    p.lastname LIKE '%user_submitted_data%' OR 
    p.fullname LIKE '%user_submitted_data%'; 

Fakat, wildcard ile LIKE korkunç bir çözümdür . Bir FULLTEXT dizini kullanarak düşünmek gerekir:

CREATE FULLTEXT INDEX people_names ON people(firstname, lastname); 

SELECT * 
FROM people 
WHERE MATCH(firstname, lastname) AGAINST(?); 

PS: FULLTEXT indeksleri MyISAM depolama motoru ile çalışır. Başka bir çözüm, daha hızlı, tam metin dizini için Sphinx Search kullanmaktır.

0

Bir alt sorgunun iyi kullanılmasına rağmen, herhangi bir dizin oluşturmamanız nedeniyle bir etkisi olacaktır.

Tabloya bir hesaplanmış sütun (firstname || ' ' || lastname) ekleme ve buna bir dizin ekleme hakkında ne var? Elbette çok daha hızlı olurdu.

ben

WHERE firstname || ' ' || lastname LIKE '%user_submitted_data%' 

gibi sorgulama hala iki OR s ve bir alt sorgu daha hızlı çalışması gerektiğini düşünüyorum yapamıyorsan.

+0

MySQL'de dizinlenmiş bir hesaplama sütunu yapmak için bir yol olduğunu düşünmüyorum, ya da benim araştırmalarımı göster. Eğer bu mümkün ise, bunu duymak isterim. – Jimmy

+0

Haklı olabilirsiniz, bence hiç hesaplanmış sütun kullanmanın bir yolu yok! – Sklivvz

+0

Bu arada MySQL, dizinlenmiş hesaplanmış sütunları destekler. Ancak, desen bir yer tutucu ile başlarsa ('' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' –

7

Tüm koşulları yalnızca HAVING maddesine yerleştirin.

SELECT [some fields], CONCAT(firstname, ' ', 'lastname') as fullname 
FROM people 
HAVING firstname LIKE '%user_submitted_data%' 
OR  lastname LIKE '%user_submitted_data%' 
OR  fullname LIKE '%user_submitted_data%

WHERE fıkra erken satırları atmak olabilir, ama sonra hesaplanmış bir sütun üzerinde koşulu değerlendirdik kadar bunları gözardı edemeyiz ve bu HAVING kadar beklemek zorunda olduğundan, bu size WHERE kullanmak için hiçbir şey satın alır .

+0

Benim için çalıştı, alt sorgular kullanmaktan çok daha zarif bir çözüm gibi görünüyor. Teşekkür ederim! –

İlgili konular