Compartir a través de

参数标记

参数标记是已命名的未命名的类型化占位符变量,用于从调用 SQL 语句的 API 提供值。

使用参数标记可保护代码免受 SQL 注入攻击,因为它能够明确地将提供的值与 SQL 语句分开。

不能在同一 SQL 语句中混合已命名和未命名的参数标记。

不得在 DDL 语句(例如生成的列或 DEFAULT 定义、视图或 SQL 函数)中引用参数标记。

例外情况是对 IDENTIFIER 子句中的参数标记的引用,这些参数标记可用于参数化某些 DDL 语句中的表或列名称。 请参见 IDENTIFIER 子句

可通过以下方式提供参数标记:

已命名的参数标记

适用于:Databricks Runtime check marked yes 12.1 及更高版本

已命名的参数标记是类型化占位符变量。 调用 SQL 语句的 API 必须提供名称/值对,以便将每个参数标记与值相关联。

语法

 :parameter_name

参数

说明

可以在同一 SQL 语句中多次引用同一参数标记。 如果没有任何值绑定到参数标记,则会引发 UNBOUND_SQL_PARAMETER 错误。 不需要引用所有提供的参数标记。

强制前置的 :(冒号)将已命名的参数标记的命名空间与列名和 SQL 参数的命名空间区分开来。

示例

以下示例定义两个参数标记:

  • later:值为 3 的 INTERVAL HOUR
  • x:值为 15.0 的 DOUBLE

x 被多次引用,而 later 被引用一次。

SQL

> DECLARE stmtStr = 'SELECT current_timestamp() + :later, :x * :x AS square';
> EXECUTE IMMEDIATE stmtStr USING INTERVAL '3' HOURS AS later, 15.0 AS x;
  2024-01-19 16:17:16.692303  225.00

Scala

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark named parameter marker example")
  .getOrCreate()

val argMap = Map("later" -> java.time.Duration.ofHours(3), "x" -> 15.0)
spark.sql(
  sqlText = "SELECT current_timestamp() + :later, :x * :x AS square",
  args = argMap).show()
// +----------------------------------------+------+
// |current_timestamp() + INTERVAL '03' HOUR|square|
// +----------------------------------------+------+
// |                    2023-02-27 17:48:...|225.00|
// +----------------------------------------+------+

Java

import org.apache.spark.sql.*;
import static java.util.Map.entry;

SparkSession spark = SparkSession
  .builder()
  .appName("Java Spark named parameter marker example")
  .getOrCreate();

Map<String, String> argMap = Map.ofEntries(
  entry("later", java.time.Duration.ofHours(3)),
  entry("x", 15.0)
);

spark.sql(
  sqlText = "SELECT current_timestamp() + :later, :x * :x AS square",
  args = argMap).show();
// +----------------------------------------+------+
// |current_timestamp() + INTERVAL '03' HOUR|square|
// +----------------------------------------+------+
// |                    2023-02-27 17:48:...|225.00|
// +----------------------------------------+------+

Python

spark.sql("SELECT :x * :y * :z AS volume", args = { "x" : 3, "y" : 4, "z"  : 5 }).show()
// +------+
// |volume|
// +------+
// |    60|
// +------+

未命名的参数标记

适用于:Databricks Runtime check marked yes 13.3 及更高版本

未命名的参数标记是类型化占位符变量。 调用 SQL 语句的 API 必须提供参数数组,以按参数标记的出现顺序将每个参数标记与值相关联。

语法

 ?

参数

  • ?:以问好标识符的形式引用提供的参数标记。

说明

每次出现未命名的参数标记时,都会使用 API 提供的值,按顺序调用 SQL 语句。 如果没有任何值绑定到参数标记,则会引发 UNBOUND_SQL_PARAMETER 错误。 不需要使用提供的所有值。

示例

以下示例定义 3 个参数标记:

  • 一个 INTERVAL HOUR 值为 3。
  • 两个 DOUBLE 值各为 15.0。

由于参数未命名,因此每个提供的值最多由一个参数使用。

SQL

> DECLARE stmtStr = 'SELECT current_timestamp() + ?, ? * ? AS square';
> EXECUTE IMMEDIATE stmtStr USING INTERVAL '3' HOURS, 15.0, 15.0;
  2024-01-19 16:17:16.692303  225.00

Scala

import org.apache.spark.sql.SparkSession

val spark = SparkSession
  .builder()
  .appName("Spark unnamed parameter marker example")
  .getOrCreate()

val argArr = Array(java.time.Duration.ofHours(3), 15.0, 15.0)

spark.sql(
  sqlText = "SELECT current_timestamp() + ?, ? * ? AS square", args = argArr).show()
// +----------------------------------------+------+
// |current_timestamp() + INTERVAL '03' HOUR|square|
// +----------------------------------------+------+
// |                    2023-02-27 17:48:...|225.00|
// +----------------------------------------+------+

Java

import org.apache.spark.sql.*;

SparkSession spark = SparkSession
  .builder()
  .appName("Java Spark unnamed parameter marker example")
  .getOrCreate();

Object[] argArr = new Object[] { java.time.Duration.ofHours(3), 15.0, 15.0 }

spark.sql(
  sqlText = "SELECT current_timestamp() + ?, ? * ? AS square",
  args = argArr).show();
// +----------------------------------------+------+
// |current_timestamp() + INTERVAL '03' HOUR|square|
// +----------------------------------------+------+
// |                    2023-02-27 17:48:...|225.00|
// +----------------------------------------+------+

Python

spark.sql("SELECT ? * ? * ? AS volume", args = { 3, 4, 5 }).show()
// +------+
// |volume|
// +------+
// |    60|
// +------+