适用于:
Databricks SQL
Databricks Runtime
参数标记是 命名 或 未命名 的类型占位符变量,用于从调用 SQL 语句的 API 提供值。
使用参数标记可保护代码免受 SQL 注入攻击,因为它清楚地将提供的值与 SQL 语句的结构分开。
不能在同一 SQL 语句中混合命名和未命名的参数标记。
还可以在 IDENTIFIER 子句中使用参数标记,这些标记可用于参数化 对象名称。 请参阅 IDENTIFIER 条款。
可以通过以下方法提供参数标记:
- Databricks SQL 通过 语句执行 API。
- Python 使用其 pyspark.sql.SparkSession.sql() API。
- Scala 使用其 org.apache.spark.sql.SparkSession.sql() API。
- Java 使用其 org.apache.spark.sql.SparkSession.sql() API。
下列规则适用:
适用于:
Databricks SQL
Databricks Runtime 17.3 LTS 及更早版本- 可以在表达式中引用参数标记
- 不得引用 DDL 语句中的参数标记,例如生成的列或
DEFAULT定义、视图或 SQL 函数。 例外是对IDENTIFIER子句中的参数标记的引用,它们可用于对某些DDL语句的主题进行参数化。 请参阅 IDENTIFIER 条款。
适用于:
Databricks Runtime 18.0 及更高版本- 你可以在可以使用参数标记类型的字面值的任何地方引用参数标记。 这会提升上述 DDL 限制,允许在生成的列、
DEFAULT定义、视图、SQL 函数和字符串值 DDL 子句(例如LOCATION)中使用参数标记。
- 你可以在可以使用参数标记类型的字面值的任何地方引用参数标记。 这会提升上述 DDL 限制,允许在生成的列、
命名参数标记
适用于: Databricks Runtime
12.1及更高版本
命名参数标记是类型化的占位符变量。 调用 SQL 语句的 API 必须提供名称/值对,以便将每个参数标记与一个值相关联。
Syntax
:parameter_name
参数
-
对提供的参数标记的引用,其形式为未限定标识符。
注释
可以在同一 SQL 语句中多次引用相同的参数标记。 如果没有值绑定到参数标记,则会引发 UNBOUND_SQL_PARAMETER 错误。 无需引用所有提供的参数标记。
前面的必需 :(冒号)用于区分命名参数标记的命名空间与列名称和 SQL 参数的命名空间。
例子
以下示例定义了两个参数标记:
-
稍后: 一个值为 3 的
INTERVAL HOUR。 -
x:值为 15.0 的 A
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 current_timestamp() + :later, :x * :x AS square",
args = { "later": datetime.timedelta(hours=3), "x": 15.0 }).show()
// +----------------------------------------+------+
// |current_timestamp() + INTERVAL '03' HOUR|square|
// +----------------------------------------+------+
// | 2023-02-27 17:48:...|225.00|
// +----------------------------------------+------+
适用于: Databricks Runtime
18.0 及更高版本
> EXECUTE IMMEDIATE 'SELECT 1::DECIMAL(:precision, :scale)' USING 6 AS precision, 4 AS scale;
1.0000
> EXECUTE IMMEDIATE 'CREATE VIEW v(c1 INT) AS SELECT :val AS c1' USING 10 AS val;
> SELECT * FROM v;
10
> EXECUTE IMMEDIATE 'CREATE TABLE T(c1 INT DEFAULT :def COMMENT \'This is a \' :com)' USING 17 AS def, 'comment' AS com;
未命名的参数标记
适用于: Databricks Runtime
”13.3 及更高版本
未命名的参数标记是类型化的占位符变量。 调用 SQL 语句的 API 必须提供一个参数数组,以便将每个参数标记与它们的显示顺序中的值相关联。
Syntax
?
参数
-
?:对提供的参数标记的引用,格式为问号。
注释
每个未命名参数标记都会顺序使用 API 提供给 SQL 语句的值。 如果未将值绑定到参数标记,则会引发 UNBOUND_SQL_PARAMETER 错误。 无需使用所有提供的值。
例子
以下示例定义了三个参数标记:
- 一个值为 3 的
INTERVAL HOUR。 - 两个
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|
// +------+
适用于: Databricks Runtime
18.0 及更高版本
> EXECUTE IMMEDIATE 'SELECT 1::DECIMAL(?, ?)' USING 6, 4;
1.0000
> EXECUTE IMMEDIATE 'CREATE VIEW v(c1 INT) AS SELECT ? AS c1' USING 10;
> SELECT * FROM v;
10
> EXECUTE IMMEDIATE 'CREATE TABLE T(c1 INT DEFAULT ? COMMENT \'This is a \' ?)' USING 17, 'comment';
DDL 字符串子句中的参数标记
某些 DDL 子句(如 LOCATION 子句) CREATE TABLE接受字符串文本而不是标识符。 不能 IDENTIFIER 将这些子句用于这些子句,因为它们不是对象名称。
适用于: Databricks Runtime
18.0 及更高版本
在 Databricks Runtime 18.0 及更高版本中,可以直接在这些子句中使用参数标记,因为 Databricks Runtime 在接受相同类型的文本时都支持参数标记。 例如:
SQL
> CREATE EXTERNAL TABLE my_table USING DELTA LOCATION :path;
Python
spark.sql(
"CREATE EXTERNAL TABLE my_table USING DELTA LOCATION :path",
args = {"path": "abfss://container@account.dfs.core.windows.net/data"})
Scala
val argMap = Map("path" -> "abfss://container@account.dfs.core.windows.net/data")
spark.sql(
sqlText = "CREATE EXTERNAL TABLE my_table USING DELTA LOCATION :path",
args = argMap)
Java
Map<String, String> argMap = Map.ofEntries(
entry("path", "abfss://container@account.dfs.core.windows.net/data")
);
spark.sql(
sqlText = "CREATE EXTERNAL TABLE my_table USING DELTA LOCATION :path",
args = argMap);
对于 18.0 之前的 Databricks Runtime 版本
适用于:
Databricks SQL
”,Databricks Runtime 14.3 到 17.3 LTS
在 Databricks Runtime 18.0 之前的版本中,Databricks Runtime 不允许在 DDL 语句中直接使用参数标记(除非通过 IDENTIFIER 子句)。 可用于 EXECUTE IMMEDIATE 动态生成 SQL 语句,将路径值串联为字符串文本:
> DECLARE path STRING DEFAULT 'abfss://container@account.dfs.core.windows.net/data';
> EXECUTE IMMEDIATE 'CREATE EXTERNAL TABLE my_table USING DELTA LOCATION \'' || path || '\'';
注释
不能在字符串文本中嵌入参数标记(例如 'abfss://:param/path')。 而是将整个字符串作为单个参数传递,或使用字符串串联在传递值之前生成该值。 例如,用于SET VARIABLECONCAT()在变量中生成完整路径,然后将变量EXECUTE IMMEDIATE传递给 。