Hive删除分区名称中含有特殊字符
先说方案:通过show partitions和hdfs url看到的都不是真正的分区名称,都是经过URI重新编码的,访问这些分区应该使用分区名称的原始字符串。
场景描述
当我们在SQL语句中使用变量时,很可能因为操作不当,导致变量并没有被替换掉,而是被直接当作分区名称。
查看分区信息
show partitions tableA;
ymd=$%25257Benv%25253ADATE_BEFORE_1DAY}
ymd=$%257Benv%253ADATE_BEFORE_1DAY}
ymd=$%7Benv%3ADATE_BEFORE_1DAY}
删除分区
alter table tableA drop partition (ymd='$%25257Benv%25253ADATE_BEFORE_1DAY}'); # 实际未删除
alter table tableA drop partition (ymd="$%25257Benv%25253ADATE_BEFORE_1DAY}"); # 实际未删除
alter table tableA drop partition (ymd='$%257Benv%253ADATE_BEFORE_1DAY}'); # 实际删除ymd=$%25257Benv%25253ADATE_BEFORE_1DAY}
alter table tableA drop partition (ymd='$%7Benv%3ADATE_BEFORE_1DAY}'); # 实际删除ymd=$%257Benv%253ADATE_BEFORE_1DAY}
原因
分区字段中含有特殊字符时,将会被(根据URI编码规范)重新编码,所以上面show partition时看到的分区名称是经过重新编码的,删除时我们需要使用原始值。
字符 | 编码后 |
---|---|
% | %25 |
: | %3A |
{ | %7B |
# | %23 |
所以,上面的分区原始值是
ymd=$%257Benv%253ADATE_BEFORE_1DAY}
ymd=$%7Benv%3ADATE_BEFORE_1DAY}
ymd=${env:DATE_BEFORE_1DAY}
三个分区从下往上,依次是作为分区字符串再次覆盖写入数据时,{和%被再次转义的结果。所以drop语句是
alter table tableA drop partition (ymd='$%257Benv%253ADATE_BEFORE_1DAY}');
alter table tableA drop partition (ymd='$%7Benv%3ADATE_BEFORE_1DAY}');
alter table tableA drop partition (ymd='$\{env:DATE_BEFORE_1DAY}'); # {必须被转义,否则${}会将后边的内容识别成变量
注意
- 只需要重新编码一次,当出现连续%2525时,仅处理第一个%25,不要连续处理
查看分区对应的HDFS存储路径
DESCRIBE FORMATTED tableA PARTITION(ymd='$%257Benv%253ADATE_BEFORE_1DAY}'); # 对应 show partitions 结果ymd=$%25257Benv%25253ADATE_BEFORE_1DAY}
col_name | data_type |
---|---|
# Detailed Partition Information | NULL |
Partition Value: | [$%257Benv%253ADATE_BEFORE_1DAY}] |
Location: | hdfs://nssit/user/hive/warehouse/bs_core/tableA/ymd=$%25257Benv%25253ADATE_BEFORE_1DAY} |
DESCRIBE FORMATTED tableA PARTITION(ymd='$\{env:DATE_BEFORE_1DAY}'); # 对应 show partitions 结果ymd=$%7Benv%3ADATE_BEFORE_1DAY}
col_name | data_type |
---|---|
# Detailed Partition Information | NULL |
Partition Value: | [${env:DATE_BEFORE_1DAY}] |
Location: | hdfs://nssit/user/hive/warehouse/bs_core/tableA/ymd=$%7Benv%3ADATE_BEFORE_1DAY} |