參數標記

適用於:勾選為「是」Databricks SQL 勾選為「是」Databricks Runtime

參數標記可以是 名為 的,或是 未命名的 型別佔位符變數,用來提供從 API 叫用 SQL 語句時所需的值。

使用參數標記可以保護你的程式碼免受 SQL 注入攻擊,因為它清楚將提供的值與 SQL 語句的結構分開。

您無法在相同的 SQL 語句中混合具名和未命名的參數標記。

你也可以在子 IDENTIFIER 句中使用參數標記,用來參數化 物件名稱。 請參閱 IDENTIFIER 子句

參數標記可以透過以下方式提供:

適用的規則如下:

  • 適用於:勾選標記為是 Databricks SQL 勾選是 Databricks 執行時間 17.3 LTS 及更早版本

    • 你可以在表達式中引用參數標記
    • 您不得參考 DDL 語句中的參數標記,例如產生的數據行或 DEFAULT 定義、檢視或 SQL 函式。 例外是子句中引用的參數標記IDENTIFIER,可以用於對某些 DDL 語句的主體進行參數化。 請參閱 IDENTIFIER 子句
  • 適用於:勾選標記為是 Databricks 執行時間 18.0 及以上版本

    • 你可以在任何需要使用參數標記類型的字面值的地方引用參數標記。 此舉解除了先前的 DDL 限制,允許在產生的欄位、定義、 DEFAULT 視圖、SQL 函式及字串值 DDL 子句中使用參數標記,如 LOCATION

具名參數標記

適用於: Databricks Runtime 已勾選為是 12.1 以上

具名參數標記是具類型的佔位符變數。 叫用 SQL 語句的 API 必須提供名稱/值組,讓每個參數標記與值產生關聯。

語法

 :parameter_name

參數

筆記

您可以在相同的 SQL 語句內多次參考相同的參數標記。 如果沒有值系結至參數標記,就會引發 UNBOUND_SQL_PARAMETER 錯誤。 您不需要參考所有提供的參數標記。

強制使用的前置 :(冒號)將具名參數標記的命名空間與數據行名稱和 SQL 參數的命名空間區分開來。

例子

下列範例會定義兩個參數標記:

  • 後來:一個值為 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 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 必須提供自變數陣列,以便讓每個參數標記與其出現的順序產生關聯。

語法

 ?

參數

  • ?:參考一個以問號形式提供的參數標記。

筆記

未命名的參數標記每次出現時,會依序取用由 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 執行版本

適用於:已勾選為是 ,Databricks SQL 勾選為是 ,Databricks 執行時間 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 || '\'';

Note

你無法將參數標記嵌入字串文字中(例如, 'abfss://:param/path')。 相反地,將整串串視為單一參數傳遞,或使用串接方式建立該值再傳遞。 例如,使用 SET VARIABLECONCAT() 建立變數的完整路徑,然後將變數傳給 EXECUTE IMMEDIATE