在 spark.sql 的选择中使用 cast()
Posted
技术标签:
【中文标题】在 spark.sql 的选择中使用 cast()【英文标题】:Using cast() inside a select in spark.sql 【发布时间】:2021-11-24 20:17:34 【问题描述】:我正在尝试做一件简单的事情:两个表之间的内部连接,但其中一个表的列已重命名,并且 data_type 错误。所以我想使用 cast() 并更改列的名称。 我这样做了:
spark.sql(f'''SELECT nr_cpf_base_srf as nr_cpf,
cd_fon_ren,
dt_ref_ren,
vl_ren,
dt_incl_ren_avld,
dt_bxa_ren,
cd_usu_rsp_atl,
cast(nr_cpf AS decimal (14,0))
FROM DB2DFE.REN_AVLD_PF as A
INNER JOIN sbx_d4n0cbf.pss_cpf_cli_msl as B
ON a.nr_cpf = b.NR_CPF
''').createOrReplaceTempView('temp_x')
表DB2DFE.REN_AVLD_PF
有一个列nr_cpf_base_srf
,我想将其更改为nr_cpf
,这样我就可以使用sbx_d4n0cbf.pss_cpf_cli_msl
构建内部连接。但是nr_cpf_base_srf
的数据类型是正确的:它应该是十进制(14,0),因此我使用了cast()
。它引发了错误:
SparkStatementException: "cannot resolve '`a.nr_cpf`' given input columns: [B.dt_mvtc, A.dt_bxa_ren, B.NR_CPF,
B.cd_cli, A.dt_incl_ren_avld, A.cd_fon_ren, A.vl_ren, A.cd_usu_rsp_atl, A.dt_ref_ren, A.nr_cpf_base_srf];
line 11 pos 17;
这一定是一件非常简单的事情,但我不知道该怎么做,也找不到任何答案。所以:怎么了?请。
【问题讨论】:
您说该列是nr_cpf_base_srf
,但您的SQL 使用nr_cpf
- 它们是不同的名称。
是的,但我选择了“nr_cpf_base_srf”作为“nr_cpf”。不对吗?第一行,我想,这样做,不是吗?
您不能在同一 SELECT
投影子句中引用其他列。只有 mysql 允许您这样做,但它违反了 ISO SQL。 Apache Spark 不允许。
然后我用我想要的新类型投射它。但我不确定如何将 nr_cpf_base_srf
选择为 nr_cpf
好的,我明白了。因此我需要在另一个子句上更改选择之前的列名?我的意思是,我调用一个 select 来更改名称,然后调用一个新的 select 来执行我想要的查询?
【参考方案1】:
ISO SQL(Apache Spark 实现,大部分)不允许您从同一 SELECT
投影子句引用其他列或表达式。
所以你不能这样做:
SELECT
( a + 123 ) AS b,
( b + 456 ) AS c
FROM
someTable
(可以说,ISO SQL应该允许这样做,否则你需要一个 CTE 或外部查询,这将扩大你的查询的文本大小:ISO SQL 设计委员会需要开始考虑他们的自己的人体工程学)。
无论如何,将您的查询更改为不引用列表达式:
SELECT
nr_cpf_base_srf AS nr_cpf,
cd_fon_ren,
dt_ref_ren,
vl_ren,
dt_incl_ren_avld,
dt_bxa_ren,
cd_usu_rsp_atl,
CAST( nr_cpf_base_srf AS decimal (14,0) )
FROM
DB2DFE.REN_AVLD_PF AS a
INNER JOIN sbx_d4n0cbf.pss_cpf_cli_msl AS b ON a.nr_cpf = b.NR_CPF
如果你真的想在CAST
之前 为该列起别名,那么你需要一个外部查询:
SELECT
t.*,
CAST( t.nr_cpf AS decimal (14,0) )
FROM
(
SELECT
nr_cpf_base_srf AS nr_cpf,
cd_fon_ren,
dt_ref_ren,
vl_ren,
dt_incl_ren_avld,
dt_bxa_ren,
cd_usu_rsp_atl
FROM
DB2DFE.REN_AVLD_PF as A
INNER JOIN sbx_d4n0cbf.pss_cpf_cli_msl AS B ON a.nr_cpf_base_srf = b.NR_CPF
) AS t
或 CTE:
WITH t AS (
SELECT
nr_cpf_base_srf AS nr_cpf,
cd_fon_ren,
dt_ref_ren,
vl_ren,
dt_incl_ren_avld,
dt_bxa_ren,
cd_usu_rsp_atl
FROM
DB2DFE.REN_AVLD_PF as A
INNER JOIN sbx_d4n0cbf.pss_cpf_cli_msl AS B ON a.nr_cpf_base_srf = b.NR_CPF
)
SELECT
t.*,
CAST( t.nr_cpf AS decimal (14,0) )
FROM
t
【讨论】:
它不工作。引发的异常引用了我最终不想要的sbx_d4n0cbf.pss_cpf_cli_msl
的某些列。也许我的问题比我预期的要大。
@Dimitri 除非您发布该新异常的全部详细信息,否则我无法为您提供更多帮助
和之前一样,其实是:SparkStatementException: "cannot resolve '
a.nr_cpf' given input columns: [a.dt_incl_ren_avld, a.cd_fon_ren, b.cd_cli, a.vl_ren, b.NR_CPF, a.dt_ref_ren, a.cd_usu_rsp_atl, a.dt_bxa_ren, a.nr_cpf_base_srf, b.dt_mvtc]; line 12 pos 63;
它引用了b.dt_mvtc
,这是第二个表中的一列
@Dimitri 啊,我错过了。我已更新我的答案以在JOIN
条件中使用nr_cpf_base_srf
,因为ISO SQL 也不允许查询引用JOIN
条件中的列表达式。以上是关于在 spark.sql 的选择中使用 cast()的主要内容,如果未能解决你的问题,请参考以下文章
hivesql 迁移spark3.0 sparksql报错如Cannot safely cast '字段':StringType to IntegerType的问题
如何使用 Spark SQL 在 Parquet 文件中选择嵌套数组和映射