Hive中LIKE查詢使用萬用字元'%'的一個BUG--當轉義符'\'遇到萬用字元'%'或'_'
在Hive開發過程中遇到這樣一個問題:
例如表T001的欄位col1裡面存有’ABC\DEF’這樣的資料,在Oracle中,我可以通過下面這樣的SQL將其查出:
SELECT * FROM T001 WHERE COL1 LIKE ‘ABC\%’;
‘\’不會將’%’進行轉義,因為沒有使用ESCAPE ‘\’ 語法。
但是到了Hive裡就不行了,
SELECT * FROM T001 WHERE COL1 LIKE ‘ABC\%’;
不會得到想要的結果。不過Hive有些特別,因為’\’預設就是轉義字元,因此,其實和上面Oracle中等價的寫法應該是對’\’轉義一次,即:
SELECT * FROM T001 WHERE COL1 LIKE ‘ABC\\%’;
但是很遺憾,還是得不到想要的結果。
為了一探究竟,我做了些簡單的實驗:
在Hive中插入一條記錄(省略部分列印資訊):
hive> INSERT OVERWRITE TABLE T001 SELECT '\\' FROM DUAL;
1 Rows loaded to T001
OK
hive> SELECT * FROM T001;
OK
\
然後進行LIKE查詢測試:
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\';
OK
\
這一步查詢在意料當中,再加入'%'試一下:
hive> SELECT * FROM T001 WHERE COL1 LIKE '%\\';
OK
\
可以看到,將’%’放到前面沒有問題,再把’%’放到後面看看行不行:
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\%';
OK
這回問題暴露了,沒有查出結果。
我猜想,Hive解析時是用’\’把’%’給轉義了,於是測試了一下:
hive> INSERT OVERWRITE TABLE T001 SELECT '%' FROM DUAL;
1 Rows loaded to T001
OK
hive> SELECT * FROM T001;
OK
%
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\%';
OK
%
結果果然不出所料!
但問題是,我現在想讓’%’作為萬用字元,而不想讓’\’將其轉義,難道就做不到嗎?Hive裡沒有ESCAPE語法,不能通過這種方法解決了,在嘗試一下其他方法:既然’\’是轉義字元,能把’%’轉義掉,那可不可以多加一個’\’把’\’給轉義了呢?
SELECT * FROM T001 WHERE COL1 LIKE ‘ABC\\\\%’;
結果還是不行!
於是我又測試了一個小例子:
hive> INSERT OVERWRITE TABLE T001 SELECT '\\\\' FROM DUAL;
1 Rows loaded to T001
OK
hive> SELECT * FROM T001;
OK
\\
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\\\';
OK
\\
恩,不出所料。
hive> SELECT * FROM T001 WHERE COL1 LIKE '%\\';
OK
\\
還是不出所料。
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\%';
OK
這個已經知道查不出來了,因為上面的實驗已經證明這個查詢匹配到的是’%’
hive> SELECT * FROM T001 WHERE COL1 LIKE '\\\\%';
OK
還是查不出來,進一步實驗可以得知這個查詢匹配到的是’\%’
於是我得出結論:
‘\’與’%’連在一起用在LIKE中時,’\’總是將’%’轉義成普通字元,即’%’失去了萬用字元的作用。本來’\’轉義應該是從左向右解析的,但是當’\’遇到’%’時似乎優先順序更高,總是優先和’%’結合。
可想而知,萬用字元’_’也有同樣的問題。
我認為這應該算是Hive的一個BUG。
如果確實想寫和Oracle中等價的查詢:
SELECT * FROM T001 WHERE COL1 LIKE ‘ABC\\%’;
建議在Hive中用正則實現:
SELECT * FROM T001 WHERE COL1 REGEXP ‘^ABC\\’;