MariaDB 中生成的列定义中的用户定义函数?
User Defined Function in generated column definition in MariaDB?
根据文档,MariaDB 允许在生成的列定义中使用用户定义的函数https://mariadb.com/kb/en/generated-columns/
User-defined functions (UDFs) are supported in expressions for generated columns. However, MariaDB can't check whether a UDF is deterministic, so it is up to the user to be sure that they do not use non-deterministic UDFs with VIRTUAL generated columns.
我使用的是 MariaDB 10.3.20,我已经创建了一个确定性函数,但在尝试创建该字段时失败了。这是一些示例代码。
CREATE TABLE `json_virt` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`json_arr` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ;
INSERT INTO json_virt SET json_arr = '["a","b"]' ;
INSERT INTO json_virt SET json_arr = '["c","d"]' ;
DELIMITER //
CREATE OR REPLACE FUNCTION `test`.`json_implode`(`data` TEXT, `sep` TEXT)
RETURNS text
CHARSET utf8mb4
COLLATE utf8mb4_unicode_ci
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE i INT UNSIGNED DEFAULT 0 ;
DECLARE v_count INT UNSIGNED DEFAULT JSON_LENGTH(data) ;
DECLARE v_current_item BLOB DEFAULT NULL ;
DECLARE v_current_path BLOB DEFAULT NULL ;
DECLARE sep_length INT UNSIGNED DEFAULT CHAR_LENGTH(sep) ;
DECLARE str TEXT DEFAULT '' ;
WHILE i < v_count DO
SET v_current_path = CONCAT('$[', i, ']') ;
SET v_current_item = JSON_EXTRACT(data, v_current_path) ;
SET v_current_item = JSON_UNQUOTE(v_current_item) ;
SET str = CONCAT(str, sep, v_current_item) ;
SET i := i + 1;
END WHILE;
SET str = SUBSTRING(str, sep_length+1) ;
RETURN str ;
END //
DELIMITER ;
SELECT
json_virt.*,
json_implode(json_virt.json_arr, ', ') AS json_imp
FROM json_virt
;
ALTER TABLE `json_virt` ADD `json_str` TEXT AS (json_implodex(json_arr, ', ')) VIRTUAL ;
ALTER TABLE `json_virt` ADD `json_str1` TEXT AS json_implode('["x","y"]', ', ') VIRTUAL ;
json_implode() 函数工作得很好,正如您在 SELECT 语句中看到的那样,但是当尝试执行最后两个 ALTER TABLE 语句时,都失败了。
我从几个不同的角度对此感兴趣:
- 为什么这不起作用?
- 适用于生成的列定义的 UDF 示例是什么?
- 是否可以在生成的列定义中使用多行或更复杂的代码?
- 有没有更好的方法来完成我正在尝试做的事情(取一个 JSON 数组的字段并将其内爆,以便每个项目都用逗号分隔为字符串)?
我看到很多开发人员在表示 MySQL/MariaDB 所谓的 Stored Function 时使用“UDF”。即,用基于ANSI SQL的语言编写并动态部署在运行 MySQL服务器上的例程。
而术语 UDF 被 MySQL/MariaDB 用于完全不同的功能。
https://mariadb.com/kb/en/create-function-udf/ 说:
A user-defined function (UDF) is a way to extend MariaDB with a new function that works like a native (built-in) MariaDB function such as ABS() or CONCAT().
UDFs need to be written in C, C++ or another language that uses C calling conventions, MariaDB needs to have been dynamically compiled, and your operating system must support dynamic loading.
请注意,Microsoft SQL 服务器使用 UDF 来实现更类似于 MySQL/MariaDB 的存储函数。这可能是混淆的根源。
根据文档,MariaDB 允许在生成的列定义中使用用户定义的函数https://mariadb.com/kb/en/generated-columns/
User-defined functions (UDFs) are supported in expressions for generated columns. However, MariaDB can't check whether a UDF is deterministic, so it is up to the user to be sure that they do not use non-deterministic UDFs with VIRTUAL generated columns.
我使用的是 MariaDB 10.3.20,我已经创建了一个确定性函数,但在尝试创建该字段时失败了。这是一些示例代码。
CREATE TABLE `json_virt` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`json_arr` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ;
INSERT INTO json_virt SET json_arr = '["a","b"]' ;
INSERT INTO json_virt SET json_arr = '["c","d"]' ;
DELIMITER //
CREATE OR REPLACE FUNCTION `test`.`json_implode`(`data` TEXT, `sep` TEXT)
RETURNS text
CHARSET utf8mb4
COLLATE utf8mb4_unicode_ci
DETERMINISTIC
SQL SECURITY INVOKER
BEGIN
DECLARE i INT UNSIGNED DEFAULT 0 ;
DECLARE v_count INT UNSIGNED DEFAULT JSON_LENGTH(data) ;
DECLARE v_current_item BLOB DEFAULT NULL ;
DECLARE v_current_path BLOB DEFAULT NULL ;
DECLARE sep_length INT UNSIGNED DEFAULT CHAR_LENGTH(sep) ;
DECLARE str TEXT DEFAULT '' ;
WHILE i < v_count DO
SET v_current_path = CONCAT('$[', i, ']') ;
SET v_current_item = JSON_EXTRACT(data, v_current_path) ;
SET v_current_item = JSON_UNQUOTE(v_current_item) ;
SET str = CONCAT(str, sep, v_current_item) ;
SET i := i + 1;
END WHILE;
SET str = SUBSTRING(str, sep_length+1) ;
RETURN str ;
END //
DELIMITER ;
SELECT
json_virt.*,
json_implode(json_virt.json_arr, ', ') AS json_imp
FROM json_virt
;
ALTER TABLE `json_virt` ADD `json_str` TEXT AS (json_implodex(json_arr, ', ')) VIRTUAL ;
ALTER TABLE `json_virt` ADD `json_str1` TEXT AS json_implode('["x","y"]', ', ') VIRTUAL ;
json_implode() 函数工作得很好,正如您在 SELECT 语句中看到的那样,但是当尝试执行最后两个 ALTER TABLE 语句时,都失败了。
我从几个不同的角度对此感兴趣:
- 为什么这不起作用?
- 适用于生成的列定义的 UDF 示例是什么?
- 是否可以在生成的列定义中使用多行或更复杂的代码?
- 有没有更好的方法来完成我正在尝试做的事情(取一个 JSON 数组的字段并将其内爆,以便每个项目都用逗号分隔为字符串)?
我看到很多开发人员在表示 MySQL/MariaDB 所谓的 Stored Function 时使用“UDF”。即,用基于ANSI SQL的语言编写并动态部署在运行 MySQL服务器上的例程。
而术语 UDF 被 MySQL/MariaDB 用于完全不同的功能。
https://mariadb.com/kb/en/create-function-udf/ 说:
A user-defined function (UDF) is a way to extend MariaDB with a new function that works like a native (built-in) MariaDB function such as ABS() or CONCAT().
UDFs need to be written in C, C++ or another language that uses C calling conventions, MariaDB needs to have been dynamically compiled, and your operating system must support dynamic loading.
请注意,Microsoft SQL 服务器使用 UDF 来实现更类似于 MySQL/MariaDB 的存储函数。这可能是混淆的根源。