alter table abc add columns (stats1 map<string,string>, stats2 map<string,string>)
我用上面的查询改变了我的表。但是在检查数据后,我得到了两个额外列的 NULL。我没有得到数据。
alter table abc add columns (stats1 map<string,string>, stats2 map<string,string>)
我用上面的查询改变了我的表。但是在检查数据后,我得到了两个额外列的 NULL。我没有得到数据。
CASCADE 是解决方案。
询问:
ALTER TABLE dbname.table_name ADD columns (column1 string,column2 string) CASCADE;
这会更改表元数据的列,并将相同的更改级联到所有分区元数据。
RESTRICT
是默认值,将列更改仅限于表元数据。
正如其他人所指出的那样CASCADE
,将更改所有分区的元数据。没有CASCADE
,如果要更改旧分区以包含新列,则需要DROP
先将旧分区填充,然后再填充它们,INSERT OVERWRITE
没有DROP
将不起作用,因为元数据不会更新为新的默认元数据。
假设您已经意外运行,然后您是一个alter table abc add columns (stats1 map<string,string>, stats2 map<string,string>)
没有DROPPING 的旧分区。数据将存储在基础文件中,但如果您从配置单元中查询该表以获取该分区,它不会显示,因为元数据未更新。无需使用以下方法重新运行插入覆盖即可解决此问题:CASCADE
INSERT OVERWRITE
SHOW CREATE TABLE dbname.tblname
并复制在添加新列之前存在的所有列定义ALTER TABLE dbname.tblname REPLACE COLUMNS ({paste in col defs besides columns to add here}) CASCADE
ALTER TABLE dbname.tblname ADD COLUMNS (newcol1 int COMMENT "new col") CASCADE
作为步骤 2-3 的示例:
DROP TABLE IF EXISTS junk.testcascade ;
CREATE TABLE junk.testcascade (
startcol INT
)
partitioned by (d int)
stored as parquet
;
INSERT INTO TABLE junk.testcascade PARTITION(d=1)
VALUES
(1),
(2)
;
INSERT INTO TABLE junk.testcascade PARTITION(d=2)
VALUES
(1),
(2)
;
SELECT * FROM junk.testcascade ;
+-----------------------+----------------+--+
| testcascade.startcol | testcascade.d |
+-----------------------+----------------+--+
| 1 | 1 |
| 2 | 1 |
| 1 | 2 |
| 2 | 2 |
+-----------------------+----------------+--+
--no cascade! opps
ALTER TABLE junk.testcascade ADD COLUMNS( testcol1 int, testcol2 int) ;
INSERT OVERWRITE TABLE junk.testcascade PARTITION(d=3)
VALUES
(1,1,1),
(2,1,1)
;
INSERT OVERWRITE TABLE junk.testcascade PARTITION(d=2)
VALUES
(1,1,1),
(2,1,1)
;
--okay! because we created this table after altering the metadata
select * FROM junk.testcascade where d=3;
+-----------------------+-----------------------+-----------------------+----------------+--+
| testcascade.startcol | testcascade.testcol1 | testcascade.testcol2 | testcascade.d |
+-----------------------+-----------------------+-----------------------+----------------+--+
| 1 | 1 | 1 | 3 |
| 2 | 1 | 1 | 3 |
+-----------------------+-----------------------+-----------------------+----------------+--+
--not okay even tho we inserted =( because the metadata isnt changed
select * FROM junk.testcascade where d=2;
+-----------------------+-----------------------+-----------------------+----------------+--+
| testcascade.startcol | testcascade.testcol1 | testcascade.testcol2 | testcascade.d |
+-----------------------+-----------------------+-----------------------+----------------+--+
| 1 | NULL | NULL | 2 |
| 2 | NULL | NULL | 2 |
+-----------------------+-----------------------+-----------------------+----------------+--+
--cut back to original columns
ALTER TABLE junk.testcascade REPLACE COLUMNS( startcol int) CASCADE;
--add
ALTER table junk.testcascade ADD COLUMNS( testcol1 int, testcol2 int) CASCADE;
--it works!
select * FROM junk.testcascade where d=2;
+-----------------------+-----------------------+-----------------------+----------------+--+
| testcascade.startcol | testcascade.testcol1 | testcascade.testcol2 | testcascade.d |
+-----------------------+-----------------------+-----------------------+----------------+--+
| 1 | 1 | 1 | 2 |
| 2 | 1 | 1 | 2 |
+-----------------------+-----------------------+-----------------------+----------------+--+
要将列添加到分区表中,您需要重新创建分区。假设表是外部的并且数据文件已经包含新列,请执行以下操作: 1. 更改表添加列... 2. 重新创建分区。对于每个分区做 Drop 然后创建。新创建的分区架构将继承表架构。
或者,您可以删除表然后创建表并创建所有分区或只需运行MSCK REPAIR TABLE abc
命令即可恢复它们。Amazon Elastic MapReduce (EMR) 的 Hive 版本上的等效命令是:ALTER TABLE table_name RECOVER PARTITIONS
. 请参阅此处的手册:恢复分区
同样在 Hive 1.1.0 及更高版本中,您可以CASCADE
使用ALTER TABLE ADD|REPLACE COLUMNS
. 请参阅此处的手册:添加列
这些建议适用于外部表。
仅当您的数据已分区并且您知道最新分区的位置时,此解决方案才有效。在这种情况下,您可以执行以下操作,而不是执行恢复分区或修复成本高昂的操作:
发布一个scala代码以供参考:
def updateMetastoreColumns(spark: SparkSession, partitionedTablePath: String, toUpdateTableName: String): Unit = {
//fetch all column names along with their corresponding datatypes from latest partition
val partitionedTable = spark.read.orc(partitionedTablePath)
val partitionedTableColumns = partitionedTable.columns zip partitionedTable.schema.map(_.dataType.catalogString)
//fetch all column names along with their corresponding datatypes from currentTable
val toUpdateTable = spark.read.table(toUpdateTableName)
val toUpdateTableColumns = toUpdateTable.columns zip toUpdateTable.schema.map(_.dataType.catalogString)
//check if new columns are present in newer partition
val diffColumns = partitionedTableColumns.diff(toUpdateTableColumns)
//update the metastore with new column info
diffColumns.foreach {column: (String, String) => {
spark.sql(s"ALTER TABLE ${toUpdateTableName} ADD COLUMNS (${column._1} ${column._2})")
}}
}
这将帮助您动态查找添加到较新分区的最新列,并将其即时更新到您的元存储。