Hive:在列名中使用 Concat

Posted

技术标签:

【中文标题】Hive:在列名中使用 Concat【英文标题】:Hive: Usage of Concat in Column Name 【发布时间】:2019-04-22 21:06:58 【问题描述】:

我正在尝试从列名称为:year_2016、year_2017、year_2018 等的表中获取数据。 我不确定如何从该表中获取数据。 数据如下:

| count_of_accidents | year_2016 | year_2017 |year_2018 | 
|--------------------|-----------|-----------|----------|
| 15                 | 12        | 5         | 1        |
| 5                  | 10        | 6         | 18       |

我已经尝试过“concat”功能,但这并没有真正起作用。

我已经试过了:

select SUM( count_of_accidents * concat('year_',year(regexp_replace('2018_1_1','_','-')))) 
from table_name;

列名(year_2017 或 year_2018 等)将作为参数传递。所以,我真的不能像这样硬编码列名-

select SUM( count_of_accidents * year_2018) from table_name;

有什么办法可以做到吗?

【问题讨论】:

不是您实际问题的答案,但您的列名(年份)中基本上有数据,这只会导致很多问题,就像您当前的问题一样。如果可以更改,请将表格分成 2 个。一个 (count_of_accident, int, year, int) 和一个 (year int, value int)(例如)。然后你在year 上有一个基本的join,你的所有查询都会容易得多,你不需要每年添加一列(所以可能每年都改变你的脚本)等等。 【参考方案1】:

您可以使用regular expressions 来完成。像这样:

--create test table
create table test_col(year_2018 string, year_2019 string);

set hive.support.quoted.identifiers=none;
set hive.cli.print.header=true;

--test select using hard-coded pattern
select year_2018, `(year_)2019` from test_col;
OK
year_2018       year_2019
Time taken: 0.862 seconds

--test pattern parameter
set hivevar:year_param=2019;

select year_2018, `(year_)$year_param` from test_col;
OK
year_2018       year_2019
Time taken: 0.945 seconds

--two parameters
set hivevar:year_param1=2018;
set hivevar:year_param2=2019;

select `(year_)$year_param1`, `(year_)$year_param2`  from test_col t;
OK
year_2018       year_2019
Time taken: 0.159 seconds

--parameter contains full column_name and using more strict regexp pattern
set hivevar:year_param2=year_2019;

select `^$year_param2$` from test_col t;
OK
year_2019
Time taken: 0.053 seconds

--select all columns using single pattern year_ and four digits
select `^year_[0-9]4$`  from test_col t;
OK
year_2018       year_2019

应该计算参数并传递给hive脚本,列名不支持concat()、regexp_replace等函数。

列别名也不适用于使用正则表达式提取的列:

 select t.number_of_incidents, `^$year_param$` as year1 from test_t t;

抛出异常:

失败:SemanticException [错误 10004]:第 1:30 行无效的表别名 或列引用“^year_2018$”:(可能的列名是: number_of_incidents, year_2016, year_2017, year_2018)

我找到了一种解决方法,可以使用带有空数据集的 union all 为列命名,请参阅此测试:

create table test_t(number_of_incidents int, year_2016 int, year_2017 int, year_2018 int);
insert into table test_t values(15, 12, 5, 1); --insert test data
insert into table test_t values(5,10,6,18);

--parameter, can be passed from outside the script from command line  
set hivevar:year_param=year_2018;

--enable regex columns and print column names
set hive.support.quoted.identifiers=none;
set hive.cli.print.header=true;

--Alias column using UNION ALL with empty dataset
select sum(number_of_incidents*year1) incidents_year1 
  from
    (--UNION ALL with empty dataset to alias columns extracted
     select 0 number_of_incidents, 0 year1 where false --returns no rows because of false condition
     union all
     select t.number_of_incidents, `^$year_param$` from test_t t
    )s;

结果:

OK
incidents_year1
105
Time taken: 38.003 seconds, Fetched: 1 row(s)

UNION ALL 中的第一个查询不会影响数据,因为它不返回任何行。但它的列名成为整个 UNION ALL 数据集的名称,可以在上层查询中使用。这个技巧有效。如果您发现使用 regexp 提取的别名列的更好解决方法,请同时添加您的解决方案。

更新:

如果您可以将完整的 column_name 作为参数传递,则不需要正则表达式。 Hive 在查询执行之前按原样替换变量(不计算它们)。仅当您由于某种原因无法传递完整的列名并且像在原始查询中一样需要一些模式连接时才使用正则表达式。看这个测试:

--parameter, can be passed from outside the script from command line  
set hivevar:year_param=year_2018;

select sum(number_of_incidents*$year_param) incidents_year1 from test_t t;

结果:

OK
incidents_year1
105
Time taken: 63.339 seconds, Fetched: 1 row(s)

【讨论】:

谢谢!这个有效。我可以重命名查询中的列吗?尝试重命名时出现错误。例如:select `(year_)$year_param1` AS year1 from test_col t; 或者,因为我需要乘以另一个列值;乘法也会引发错误。 @Tanvir 欢迎您提出有趣的问题。

以上是关于Hive:在列名中使用 Concat的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HIVE JDBC 驱动程序在列名中使用特殊字符?

如何在 Hive 的所有表中找到特定的列名。?

hive中关键字作为列名的方法

如何更改 hive 中的列名

如何使用 spark 获取 hive 分区列名

如何在Hive中的所有表中找到特定的列名。