CREATE FUNCTION (SQL och Python)

Gäller för: markerad ja Databricks SQL markerad ja Databricks Runtime

Skapar en SQL-skalär- eller tabellfunktion som tar en uppsättning argument och returnerar ett skalärt värde eller en uppsättning rader.

Gäller för: markerad ja Databricks SQL markerad ja Databricks Runtime 13.3 LTS och senare

Skapar en Python-skalär funktion som tar en uppsättning argument och returnerar ett skalärt värde.

Python-UDF:er kräver Unity Catalog på serverlösa eller pro SQL-lager eller ett delat eller enstaka Unity Catalog-kluster.

Gäller för: markerad ja Databricks SQL markerad ja Databricks Runtime 14.1 och senare

Förutom anrop av positionsparametrar kan du även anropa SQL och Python UDF med hjälp av namngivna parameteranrop.

Syntax

CREATE [OR REPLACE] [TEMPORARY] FUNCTION [IF NOT EXISTS]
    function_name ( [ function_parameter [, ...] ] )
    { [ RETURNS data_type ] |
      RETURNS TABLE [ ( column_spec [, ...]) ] }
    [ characteristic [...] ]
    { AS dollar_quoted_string | RETURN { expression | query } }

function_parameter
    parameter_name data_type [DEFAULT default_expression] [COMMENT parameter_comment]

column_spec
    column_name data_type [COMMENT column_comment]

characteristic
  { LANGUAGE { SQL | PYTHON } |
    [NOT] DETERMINISTIC |
    COMMENT function_comment |
    [CONTAINS SQL | READS SQL DATA] }

Parametrar

  • ELLER ERSÄTT

    Om det anges ersätts funktionen med samma namn och signatur (antal parametrar och parametertyper). Du kan inte ersätta en befintlig funktion med en annan signatur. Detta är främst användbart för att uppdatera funktionstexten och funktionens returtyp. Du kan inte ange den här parametern med IF NOT EXISTS.

  • TEMPORÄR

    Omfånget för funktionen som skapas. När du anger TEMPORARYär den skapade funktionen giltig och synlig i den aktuella sessionen. Ingen beständig post görs i katalogen.

  • OM INTE FINNS

    Om det anges skapar funktionen endast när den inte finns. Det går att skapa funktionen (inget fel utlöses) om den angivna funktionen redan finns i systemet. Du kan inte ange den här parametern med OR REPLACE.

  • function_name

    Ett namn på funktionen. För en permanent funktion kan du eventuellt kvalificera funktionsnamnet med ett schemanamn. Om namnet inte är kvalificerat skapas den permanenta funktionen i det aktuella schemat.

  • function_parameter

    Anger en parameter för funktionen.

    • parameter_name

      Parameternamnet måste vara unikt i funktionen.

    • data_type

      Alla datatyper som stöds. För Python data_type skickas till en Python-datatyp enligt den här språkmappningen.

    • STANDARD default_expression

      Gäller för: markerad ja Databricks SQL markerad ja Databricks Runtime 10.4 LTS och senare

      Ett valfritt standardvärde som ska användas när ett funktionsanrop inte tilldelar ett argument till parametern. default_expression måste vara gjutbar till data_type. Uttrycket får inte referera till en annan parameter eller innehålla en underfråga.

      När du anger ett standardvärde för en parameter måste alla följande parametrar också ha ett standardvärde.

      DEFAULT stöds endast för LANGUAGE SQL .

    • KOMMENTAR

      En valfri beskrivning av parametern. comment måste vara en STRING literal.

  • RETURNERAR data_type

    Den skalära funktionens returdatatyp. För Python-UDF:er måste returvärden exakt matcha datatypen enligt vad som anges i data_type. Annars misslyckas funktionen för att förhindra oväntade typkonverteringar.

    För SQL UDF är den här satsen valfri. Datatypen härleds från funktionstexten om den inte tillhandahålls.

  • RETURNERAR TABELL [ (column_spec [,...] ) ]

    Den här satsen markerar funktionen som en tabellfunktion. Du kan också ange signaturen för resultatet av tabellfunktionen. Om ingen column_spec anges härleds den från brödtexten i SQL UDF.

    RETURNS TABLE stöds endast för LANGUAGE SQL .

    • column_name

      Kolumnnamnet måste vara unikt i signaturen.

    • data_type

      Alla datatyper som stöds.

    • KOMMENTAR column_comment

      En valfri beskrivning av kolumnen. comment måste vara en STRING literal.

  • RETUR { uttrycksfråga | }

    Funktionens brödtext. För en skalär funktion kan det antingen vara en fråga eller ett uttryck. För en tabellfunktion kan det bara vara en fråga. Uttrycket får inte innehålla:

    I brödtexten i funktionen kan du referera till parametern med dess okvalificerade namn eller genom att kvalificera parametern med funktionsnamnet.

  • AS-dollar_quoted_definition

    dollar_quoted_definition är Python-funktionen body omgiven av två matchande $[tag]$body$[tag]$. tag kan vara en tom sträng.

    Exempel:

    $$
      return “Hello world”
    $$
    
    $py$
      return "Hello World"
    $py$
    
  • kännetecken

    Alla egenskapssatser är valfria. Du kan ange valfritt antal av dem i valfri ordning, men du kan bara ange varje sats en gång.

    • LANGUAGE SQL eller LANGUAGE PYTHON

      Språket för funktionsimplementeringen.

    • [NOT] DETERMINISTISK

      Om funktionen är deterministisk. En funktion är deterministisk när den bara returnerar ett resultat för en viss uppsättning argument. Du kan markera en funktion som DETERMINISTIC när dess brödtext inte är och vice versa. En orsak till detta kan vara att uppmuntra eller avskräcka från frågeoptimeringar, till exempel konstant vikning eller cachelagring av frågor. Om du inte anger det här alternativet härleds det från funktionstexten.

    • KOMMENTAR function_comment

      En kommentar för funktionen. function_comment måste vara Strängliteral.

    • INNEHÅLLER SQL - eller READS SQL DATA

      Om en funktion läser data direkt eller indirekt från en tabell eller en vy. När funktionen läser SQL-data kan du inte ange CONTAINS SQL. Om du inte anger någon av satserna härleds egenskapen från funktionstexten.

Bibliotek som stöds i Python UDF:er

Om du vill använda beroenden använder du import <package> i funktionstexten. Se till exempel följande:

CREATE FUNCTION […]
AS $$
   import json
   [... (rest of function definition)]
$$

Beroenden är begränsade till python-standardbiblioteket och följande bibliotek:

Paket Version
blekmedel 4.0.0
chardet 4.0.0
charset-normalizer 2.0.4
defusedxml 0.7.1
googleapis-common-protos 1.56.4
grpcio 1.47.0
grpcio-status 1.47.0
jmespath 0.10.0
joblib 1.1.0
numpy 1.20.3
emballage 21,3
Pandas 1.3.4
Patsy 0.5.2
protobuf 4.21.5
pyarrow 7.0.0
pyparsing 3.0.9
python-dateutil 2.8.2
pytz 2021.3
scikit-learn 0.24.2”
scipy 1.7.1”
setuptools 65.2.0
sex 1.16.0
threadpoolctl 3.1.0
webencodings 0.5.1
användaragenter 2.2.0
kryptografi 38.0.4

Exempel

Skapa och använda en SQL-skalär funktion

> CREATE VIEW t(c1, c2) AS VALUES (0, 1), (1, 2);
-- Create a temporary function with no parameter.
> CREATE TEMPORARY FUNCTION hello() RETURNS STRING RETURN 'Hello World!';

> SELECT hello();
  Hello World!

-- Create a permanent function with parameters.
> CREATE FUNCTION area(x DOUBLE, y DOUBLE) RETURNS DOUBLE RETURN x * y;

-- Use a SQL function in the SELECT clause of a query.
> SELECT area(c1, c2) AS area FROM t;
 0.0
 2.0

-- Use a SQL function in the WHERE clause of a query.
> SELECT * FROM t WHERE area(c1, c2) > 0;
 1  2

-- Compose SQL functions.
> CREATE FUNCTION square(x DOUBLE) RETURNS DOUBLE RETURN area(x, x);

> SELECT c1, square(c1) AS square FROM t;
  0  0.0
  1  1.0

-- Create a non-deterministic function
> CREATE FUNCTION roll_dice()
    RETURNS INT
    NOT DETERMINISTIC
    CONTAINS SQL
    COMMENT 'Roll a single 6 sided die'
    RETURN (rand() * 6)::INT + 1;
-- Roll a single 6-sided die
> SELECT roll_dice();
 3

Skapa och använda en funktion som använder DEFAULT

-- Extend the function to support variable number of sides and dice.
-- Use defaults to support a variable number of arguments
> DROP FUNCTION roll_dice;
> CREATE FUNCTION roll_dice(num_dice  INT DEFAULT 1 COMMENT 'number of dice to roll (Default: 1)',
                            num_sides INT DEFAULT 6 COMMENT 'number of sides per die (Default: 6)')
    RETURNS INT
    NOT DETERMINISTIC
    CONTAINS SQL
    COMMENT 'Roll a number of n-sided dice'
    RETURN aggregate(sequence(1, roll_dice.num_dice, 1),
                     0,
                     (acc, x) -> (rand() * roll_dice.num_sides)::int,
                     acc -> acc + roll_dice.num_dice);

-- Roll a single 6-sided die still works
> SELECT roll_dice();
 3

-- Roll 3 6-sided dice
> SELECT roll_dice(3);
 15

-- Roll 3 10-sided dice
> SELECT roll_dice(3, 10)
 21

-- Roll 3 10-sided dice using named parameter invocation
> SELECT roll_dice(10 => num_sides, num_dice => 3)
 17

-- Create a SQL function with a scalar subquery.
> CREATE VIEW scores(player, score) AS VALUES (0, 1), (0, 2), (1, 2), (1, 5);

> CREATE FUNCTION avg_score(p INT) RETURNS FLOAT
    COMMENT 'get an average score of the player'
    RETURN SELECT AVG(score) FROM scores WHERE player = p;

> SELECT c1, avg_score(c1) FROM t;
 0  1.5
 1  3.5

Skapa en SQL-tabellfunktion

-- Produce all weekdays between two dates
> CREATE FUNCTION weekdays(start DATE, end DATE)
    RETURNS TABLE(day_of_week STRING, day DATE)
    RETURN SELECT extract(DAYOFWEEK_ISO FROM day), day
             FROM (SELECT sequence(weekdays.start, weekdays.end)) AS T(days)
                  LATERAL VIEW explode(days) AS day
             WHERE extract(DAYOFWEEK_ISO FROM day) BETWEEN 1 AND 5;

-- Return all weekdays
> SELECT weekdays.day_of_week, day
    FROM weekdays(DATE'2022-01-01', DATE'2022-01-14');
  1     2022-01-03
  2     2022-01-04
  3     2022-01-05
  4     2022-01-06
  5     2022-01-07
  1     2022-01-10
  2     2022-01-11
  3     2022-01-12
  4     2022-01-13
  5     2022-01-14

-- Return weekdays for date ranges originating from a LATERAL correlation
> SELECT weekdays.*
    FROM VALUES (DATE'2020-01-01'),
                (DATE'2021-01-01'),
                (DATE'2022-01-01') AS starts(start),
         LATERAL weekdays(start, start + INTERVAL '7' DAYS);
  3     2020-01-01
  4     2020-01-02
  5     2020-01-03
  1     2020-01-06
  2     2020-01-07
  3     2020-01-08
  5     2021-01-01
  1     2021-01-04
  2     2021-01-05
  3     2021-01-06
  4     2021-01-07
  5     2021-01-08
  1     2022-01-03
  2     2022-01-04
  3     2022-01-05
  4     2022-01-06
  5     2022-01-07

Ersätt en SQL-funktion

-- Replace a SQL scalar function.
> CREATE OR REPLACE FUNCTION square(x DOUBLE) RETURNS DOUBLE RETURN x * x;

-- Replace a SQL table function.
> CREATE OR REPLACE FUNCTION getemps(deptno INT)
    RETURNS TABLE (name STRING)
    RETURN SELECT name FROM employee e WHERE e.deptno = getemps.deptno;

-- Describe a SQL table function.
> DESCRIBE FUNCTION getemps;
 Function: default.getemps
 Type:     TABLE
 Input:    deptno INT
 Returns:  id   INT
           name STRING

Kommentar

Du kan inte ersätta en befintlig funktion med en annan signatur.

Beskriva en SQL-funktion

> DESCRIBE FUNCTION hello;
 Function: hello
 Type:     SCALAR
 Input:    ()
 Returns:  STRING

> DESCRIBE FUNCTION area;
 Function: default.area
 Type:     SCALAR
 Input:    x DOUBLE
           y DOUBLE
 Returns:  DOUBLE

> DESCRIBE FUNCTION roll_dice;
 Function: default.roll_dice
 Type:     SCALAR
 Input:    num_dice  INT
           num_sides INT
 Returns:  INT

> DESCRIBE FUNCTION EXTENDED roll_dice;
 Function:      default.roll_dice
 Type:          SCALAR
 Input:         num_dice  INT DEFAULT 1 'number of dice to roll (Default: 1)'
                num_sides INT DEFAULT 6 'number of sides per dice (Default: 6)'
 Returns:       INT
 Comment:       Roll a number of m-sided dice
 Deterministic: false
 Data Access:   CONTAINS SQL
 Configs:       ...
 Owner:         the.house@always.wins
 Create Time:   Sat Feb 12 09:29:02 PST 2022
 Body:          aggregate(sequence(1, roll_dice.num_dice, 1),
                      0,
                      (acc, x) -> (rand() * roll_dice.num_sides)::int,
                      acc -> acc + roll_dice.num_dice)

Skapa Python-funktioner

—- Hello World-like functionality using Python UDFs
> CREATE FUNCTION main.default.greet(s STRING)
  RETURNS STRING
  LANGUAGE PYTHON
  AS $$
    def greet(name):
      return "Hello " + name + "!"

    return greet(s) if s else None
  $$

—- Can import functions from std library and environment
> CREATE FUNCTION main.default.isleapyear(year INT)
  RETURNS BOOLEAN
  LANGUAGE PYTHON
  AS $$
    import calendar
    return calendar.isleap(year) if year else None
  $$

—- Must return the correct type. Otherwise will fail at runtime.
> CREATE FUNCTION main.default.a_number()
  RETURNS INTEGER
  LANGUAGE PYTHON
  AS $$
    # does not work: return "10"
    # does not work: return 3.14
    return 10
  $$

—- Deal with exceptions.
> CREATE FUNCTION main.default.custom_divide(n1 INT, n2 INT)
  RETURNS FLOAT
  LANGUAGE PYTHON
  AS $$
    try:
      return n1/n2
    except ZeroDivisionException:
    # in case of 0, we can return NULL.
    return None
  $$