在 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 Parquet统计(最小/最大)集成

如何使用 Spark SQL 在 Parquet 文件中选择嵌套数组和映射

pySpark 在 UDF 中使用 Spark SQL/DF 的最佳选择?

spark sql日期间隔sql查询不起作用

使用 $ 值 spark sql 调用列