无法通过Python执行mysql脚本-“CREATE FUNCTION”或“CREATE TRIGGER”

问题描述 投票:0回答:1

我之前编写的 sql 脚本确实遇到了麻烦,并尝试使用我的 python 代码读取并执行它。这是我的简单 mysql 脚本,其中删除了 DELIMITER 命令:

DROP FUNCTION IF EXISTS `employee_db`.`func_create_token`;

CREATE FUNCTION `employee_db`.`func_create_token`() RETURNS VARCHAR(100) DETERMINISTIC
BEGIN
    DECLARE `chars` VARCHAR(26);
    DECLARE `charLen` INT;
    DECLARE `randomPassword` VARCHAR(100);
    
    SET `chars` = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    SET `charLen` = LENGTH(`chars`);
    SET `randomPassword` = '';

    WHILE LENGTH(`randomPassword`) < 12 DO
        SET `randomPassword` = CONCAT(`randomPassword`, SUBSTRING(`chars`, CEILING(RAND() * `charLen`), 1));
    END WHILE;

    RETURN `randomPassword`;
END;

我可以直接执行它并创建函数。到目前为止没有问题。但是尝试在 python 中读取 sql 文件并执行它,总是会导致我无法解决的错误。下面你可以看到 python 函数:

# Function to execute sql file
def execute_sql_script(path_to_sql: os.PathLike[str], title: str) -> None:
    
    # Read sql file from folder `sql`
    try:
        with open(path_to_sql, 'r') as f:
            queries : list = f.read().split(';')
            queries : list = [q.strip() for q in queries if q.strip()]
        f.close()
    except FileNotFoundError as f:
        print(color.BOLD + color.RED + f'File couldn\'t be read. Please check error: {e}' + color.END)
        
    # Execute sql script with progress bar
    try:
        with alive_bar(len(queries), dual_line = True, title = title, force_tty = True) as bar:
            for _, query in enumerate(queries):
                sleep(.05)
                cursor.execute(query)
                bar()
        cursor.commit()
    except Error as e:
        print(color.BOLD + color.RED + f'Error in executing sql script. Check error: {e}' + color.END)

错误消息不是很有帮助:

Create Function - Employee |███▋⚠︎                                   | (!) 1/11 [
[1m[91mError in executing sql script. Check error: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 3[0m

奇怪的是,创建表的所有其他脚本的执行确实工作得非常好,没有任何异常。

Create Function - Employee |████████████████████████████████████████| 27/27 [100
python mysql stored-functions mysql-connector-python
1个回答
0
投票

您阅读 SQL 脚本,将输入拆分为

';'
字符上的各个 SQL 语句,然后执行每个语句。

但是 MySQL 例程在其主体中包含一个

;
字符。如果您将输入拆分为
;
字符,您会得到以下结果:

CREATE FUNCTION `employee_db`.`func_create_token`() RETURNS VARCHAR(100) DETERMINISTIC
BEGIN
    DECLARE `chars` VARCHAR(26);

这不是完整的 CREATE FUNCTION 语句。它在第一个

;
字符处提前终止,因为这是您告诉它分割输入的字符。 SQL 解析器期望
BEGIN
具有
END
,但事实并非如此。

这就是为什么简单地拆分

;
是不够的。您需要跟踪任何
BEGIN...END
块,包括嵌套块。

您还需要解析输入,以确保您没有找到作为字符串文字一部分、注释内部甚至 SQL 标识符一部分的

;
字符。

您基本上需要一个成熟的 SQL 解析器,而不仅仅是

f.read().split(';')

第二种选择是执行 MySQL 客户端在读取 SQL 脚本时执行的操作:您需要支持

DELIMITER
命令,并在 SQL 脚本中使用不是
;
或任何其他字符的分隔符在存储例程的主体中找到。您需要逐行解析输入,直到找到 current 分隔符(因为它不会是
;
)。

第三种选择是忘记编写“运行”SQL 脚本的代码,而只是分叉一个子进程来运行

mysql
客户端,该客户端已经完成了必要的解析。

这取决于你。您可以花费数小时或数天的时间编写一个用 Python 执行此操作的解析器。或者您可以运行

mysql
客户端并在五分钟内完成您的任务。

© www.soinside.com 2019 - 2024. All rights reserved.