如何编写匿名PL/SQL函数并在SQL语句中使用它
#sql #oracle #database #plsql

您是否曾经在编写SQL查询和思考中遇到过这种情况,如果我能为此编写快速的PL/SQL功能,那将使这快速简便?但是,不幸的是,您没有任何特权来创建模式中的任何功能。幸运的是,由于Oracle数据库12C,因此有一个答案。

随着Oracle数据库12.1.0.1在2013年发布,Oracle引入了编写匿名PL/SQL声明的能力,作为SQL查询的一部分。这是用WITH子句完成的,也称为 common Table表达式子句或 cte ,现在可以包含上述匿名PL/SQL声明。

让我们想象一下您有一个table products,其中包含有关各种卖家产品的信息。这看起来像这样:

CREATE TABLE products (
  id     NUMBER         NOT NULL PRIMARY KEY,
  name   VARCHAR(255)   NOT NULL,
  url    VARCHAR(255)
);

INSERT INTO products VALUES (1, 'AirPods Pro (2nd gen)', 'https://www.apple.com/shop/product/MQD83AM/A/airpods-pro');

INSERT INTO products VALUES (2, 'SanDisk - Ultra 512GB USB 3.0', 'https://www.bestbuy.com/site/sandisk-ultra-512gb-usb-3-0-flash-drive-black/6422265.p');

commit;

您想编写一个查询,例如为您提供产品名称,每种产品的出售域和URL。但是您要确保名称和域名的第一个字母始终大写。当然,您可以在纯SQL中执行此操作,但是您对PL/SQL感到满意,并且这些功能很快写入:

get_domain_name函数

FUNCTION get_domain_name
  (
    p_url VARCHAR2,
    p_sub_domain VARCHAR2 DEFAULT 'www.'
  )
  RETURN VARCHAR2
IS
  v_begin_pos BINARY_INTEGER;
  v_length    BINARY_INTEGER;
BEGIN
  v_begin_pos := INSTR(p_url, p_sub_domain) + LENGTH(p_sub_domain);
  v_length := INSTR(SUBSTR(p_url, v_begin_pos), '.') - 1;
  RETURN SUBSTR(p_url, v_begin_pos, v_length);
END;

大写功能

FUNCTION capitalize (p_string VARCHAR2)
  RETURN VARCHAR2
IS
BEGIN
  RETURN CONCAT(UPPER(SUBSTR(p_string,1,1)), SUBSTR(p_string,2));
END;

使用此新功能,您可以将这两个功能都包装到WITH子句中,并在您的SQL块中重复使用,甚至多次:

WITH
  -- Function to capitalize input string
  FUNCTION capitalize
    (
      p_string VARCHAR2
    )
    RETURN VARCHAR2
  IS
  BEGIN
    RETURN CONCAT(UPPER(SUBSTR(p_string,1,1)), SUBSTR(p_string,2));
  END;
  -- Function to retrieve the domain name from a URL
  FUNCTION get_domain_name
    (
      p_url VARCHAR2,
      p_sub_domain VARCHAR2 DEFAULT 'www.'
    )
    RETURN VARCHAR2
  IS
    v_begin_pos BINARY_INTEGER;
    v_length    BINARY_INTEGER;
  BEGIN
    v_begin_pos := INSTR(p_url, p_sub_domain) + LENGTH(p_sub_domain);
    v_length := INSTR(SUBSTR(p_url, v_begin_pos), '.') - 1;
    RETURN SUBSTR(p_url, v_begin_pos, v_length);
  END;
-- SQL statement
SELECT capitalize(name) as name, capitalize(get_domain_name(url)) AS domain_name, url
  FROM products;

在数据库中,这只是一个带有常见表表达式的SELECT语句。您不需要与您相关的用户的模式上的任何写入特权:

SQL> WITH
  2    -- Function to capitalize input string
  3    FUNCTION capitalize
  4      (
  5        p_string VARCHAR2
  6      )
  7      RETURN VARCHAR2
  8    IS
  9    BEGIN
 10      RETURN CONCAT(UPPER(SUBSTR(p_string,1,1)), SUBSTR(p_string,2));
 11    END;
 12    -- Function to retrieve the domain name from a URL
 13    FUNCTION get_domain_name
 14      (
 15        p_url VARCHAR2,
 16        p_sub_domain VARCHAR2 DEFAULT 'www.'
 17      )
 18      RETURN VARCHAR2
 19    IS
 20      v_begin_pos BINARY_INTEGER;
 21      v_length    BINARY_INTEGER;
 22    BEGIN
 23      v_begin_pos := INSTR(p_url, p_sub_domain) + LENGTH(p_sub_domain);
 24      v_length := INSTR(SUBSTR(p_url, v_begin_pos), '.') - 1;
 25      RETURN SUBSTR(p_url, v_begin_pos, v_length);
 26    END;
 27  -- SQL statement
 28  SELECT capitalize(name) as name, capitalize(get_domain_name(url)) AS domain_name, url
 29    FROM products;
 30 /

NAME                             DOMAIN_NAME    URL
________________________________ ______________ _______________________________________________________________________________________
AirPods Pro (2nd gen)            Apple          https://www.apple.com/shop/product/MQD83AM/A/airpods-pro
SanDisk - Ultra 512GB USB 3.0    Bestbuy        https://www.bestbuy.com/site/sandisk-ultra-512gb-usb-3-0-flash-drive-black/6422265.p