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\\’;

你可能感兴趣的:(IT)