代码之家  ›  专栏  ›  技术社区  ›  alexanoid

select语句中的spark in/exists谓词

  •  0
  • alexanoid  · 技术社区  · 6 年前

    我有以下Spark SQL测试查询:

    Seq("france").toDF.createOrReplaceTempView("countries")
    
    SELECT CASE WHEN country = 'italy' THEN 'Italy' 
        ELSE ( CASE WHEN country IN (FROM countries) THEN upperCase(country) ELSE country END ) 
        END AS country FROM users
    

    引发以下错误:

    Exception in thread "main" org.apache.spark.sql.AnalysisException: 
        IN/EXISTS predicate sub-queries can only be used in a Filter
    

    查询的以下部分 CASE WHEN country IN (FROM countries) 这就是原因。

    Spark SQL中是否存在用于模拟 country IN (FROM countries) 在选择的条件下?我对纯SQL实现感兴趣,而不是通过API实现。

    2 回复  |  直到 6 年前
        1
  •  1
  •   morsik    6 年前

    下面是正确的SQL查询:

    import sparkSession.implicits._
    
    Seq("france").toDF("country").createOrReplaceTempView("countries")
    Seq(("user1", "france"), ("user2", "italy"), ("user2", "usa"))
      .toDF("user", "country").createOrReplaceTempView("users")
    
    val query =
      s"""
         |SELECT
         |  CASE
         |    WHEN u.country = 'italy' THEN 'Italy'
         |    ELSE (
         |      CASE
         |        WHEN u.country = c.country THEN upper(u.country)
         |        ELSE u.country
         |      END
         |    ) END AS country
         |FROM users u
         |LEFT JOIN countries c
         |  ON u.country = c.country
      """.stripMargin
    sparkSession.sql(query).show()
    

    结果:

    +-------+
    |country|
    +-------+
    | FRANCE|
    |  Italy|
    |    usa|
    +-------+
    

    你可以使用的场景背后的原因 IN/EXISTS 仅谓词中的SQL运算符是:投影中的逻辑( CASE-WHEN 在我们的情况下) 每行评估 在从所选内容返回的数据集中。 考虑到这一点,运行等效于 CASE WHEN country IN (SELECT * FROM countries) 对于来自的每一行 users 表。因此,SQL在语言级别(SQL解析器引擎)上防止了这种情况。

        2
  •  0
  •   RudyVerboven    6 年前

    作为替代方案,您可以使用

    带列()

    当()

    函数(从 spark.sql.functions ):

    val users = Seq(("1", "france"), ("2", "Italy"), ("3", "italy")).toDF("userId", "country")
    val countriesList = Seq("france", "italy", "germany").toList
    
    val result = users.withColumn("country", when(col("country") === "italy", "Italy")
      .when(col("country") isin(countriesList:_*), upper(col("country"))).otherwise(col("country")))
    
    result.show()
    

    结果:

    +------+-------+
    |userId|country|
    +------+-------+
    |     1| FRANCE|
    |     2|  Italy|
    |     3|  Italy|
    +------+-------+
    
    推荐文章