2015-12-19 100 views
0

我想編寫一個查詢,該查詢將按照該順序獲取給定字符串及其子字符串的最近匹配字符串。使用SQL查詢查找最接近的匹配字符串及其子串

例如,可以說我有一列所有名字的表。如果我想搜索名稱"ATUL",則結果應列出匹配第一個"ATUL%",然後"ATU%",然後"AT%",然後"A%"匹配的所有不同名稱,最後是所有剩餘的記錄。

(然後我會根據我的需求回暖第N個記錄出來的)查詢

鮮明的工會是一個解決方案,我能想到的。有沒有更有效的方法來做到這一點?

UPDATE:

感謝下面的答案。同時,我試圖在我自己的東西,發現了這個查詢產生預期的結果,只要我有用戶名列索引

select * FROM all_usernames WHERE (username LIKE 'atul%') or (username LIKE 'atu%') or (username LIKE 'at%') or (username LIKE 'a%') or (username LIKE '%'); 

但它是標準的行爲,或者是它,我只是得到它巧合?

+0

雖然你不需要像「OTUL」這樣的東西嗎?我可能是錯的,但它聽起來像你想要找到最小漢明距離的字符串,而不只是相同的初始字符。 – Timekiller

+0

只有通過逐個消除最後一個字符而生成的子字符串。 – Atul

+0

看起來你想要計算字符串之間的Levenstein距離。看問題:http://stackoverflow.com/questions/634995/implementation-of-levenshtein-distance-for-mysql-fuzzy-search和實現:http://www.artfulsoftware.com/infotree/queries.php# 552 – Ingaz

回答

2

一種方法是在order by使用like

order by (case when name like 'ATUL%' then 1 
       when name like 'ATU%' then 2 
       when name like 'AT%' then 3 
       when name like 'A%' then 4 
       else 5 
      end) 

一個更通用的方法也是蠻力,但可以去這樣的事情:

order by (case when left(name, 9) = left('ATUL', 9) then 1 
       when left(name, 8) = left('ATUL', 8) then 2 
       when left(name, 7) = left('ATUL', 7) then 3 
       when left(name, 6) = left('ATUL', 6) then 4 
       when left(name, 5) = left('ATUL', 5) then 5 
       when left(name, 4) = left('ATUL', 4) then 6 
       when left(name, 3) = left('ATUL', 3) then 7 
       when left(name, 2) = left('ATUL', 2) then 8 
       when left(name, 1) = left('ATUL', 1) then 9 
      end) 
+0

感謝您的回答。與此同時,我自己嘗試了一些東西,發現'select * FROM all_usernames WHERE(username LIKE'atul%')或(username LIKE'atu%')或(username LIKE'at%')或(username LIKE'a%' )或(用戶名LIKE'%');'返回我預期的結果,我提供了_username_列**索引**但是它是標準行爲還是我剛剛得到它? – Atul

+0

@Atul。 。 。我實際上首先考慮了這樣的答案,但我認爲第一個版本更清晰。通常,索引會影響查詢的*性能*。但是,索引不會影響查詢的*語義*。也就是說,無論有沒有索引,查詢都應該做同樣的事情。 –

+0

感謝您的澄清。有了這個評論,它爲我提供了一個完整的答案:) – Atul

0

好,ATUL%ATU%AT%都是A%的子集,所以選擇A%即可獲得所有結果。棘手的部分是通過匹配多少首字符來排序。似乎沒有簡單或優雅的方法來找到這一點,所以如果你想要一些通用的東西,你必須編寫自己的函數來比較一個循環中字符串1和字符串2的子字符串,直到它們不同或字符串的長度爲達到,像這樣:

CREATE FUNCTION `compare_first_chars`(str1 varchar(1000), str2 varchar(1000)) 
    RETURNS int 
    DETERMINISTIC 
BEGIN 
    DECLARE v_offset INT; 
    DECLARE v_minlen INT; 

    IF str1 is null or str2 is null THEN 
    return 0; 
    END IF; 

    SET v_offset = 0; 

    SET v_minlen = least(length(str1), length(str2)); 

    count_loop: LOOP 
    SET v_offset = v_offset + 1; 

    IF v_offset > v_minlen THEN 
     LEAVE count_loop; 
    END IF; 

    IF substr(str1, 1, v_offset) != substr(str2, 1, v_offset) THEN 
     LEAVE count_loop; 
    END IF; 

    END LOOP; 

    RETURN v_offset-1; 
END 

那麼你可以order desc由它。如果你不需要複雜的東西,那麼或者按照你在答案中提到的順序使用CASE,或者使用不同的聯合。