使用 Python RE 模块解析 SQL 语句

Use Python RE module parse SQL Statement

最近有一项任务是解析 SQL 语句以使用 Python RE 模块和 sqlparse

的一些自定义规范检查 SQL

例如

CREATE TABLE `student_info` (
`id` INT (11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'primary',
`stu_name` VARCHAR (10) NOT NULL DEFAULT '' COMMENT 'username',
`stu_class` VARCHAR (10) NOT NULL DEFAULT '' COMMENT 'class',
`stu_num` INT (11) NOT NULL DEFAULT '0' COMMENT 'study number',
`stu_score` SMALLINT UNSIGNED NOT NULL DEFAULT '0' COMMENT 'total',
`tuition` DECIMAL (5, 2) NOT NULL DEFAULT '0' COMMENT 'fee',
`phone_number` VARCHAR (20) NOT NULL DEFAULT '0' COMMENT 'mobile',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'record created time',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'record updated time',
`status` TINYINT NOT NULL DEFAULT '1' COMMENT 'some comment',
PRIMARY KEY (`id`),
UNIQUE KEY uniq_stu_num (`stu_num`),
KEY idx_stu_score (`stu_score`),
KEY idx_update_time_tuition (`update_time`, `tuition`)
) ENGINE = INNODB charset = utf8mb4 COMMENT 'Student table';

我尝试用 RE 使用一些规范来捕捉这个语句

我使用的正则表达式模式如下:

create\s+table\s*`\w*`\s*\(\n\s*`([\w\-_]*)`\s*([\w]*).*(auto_increment)([\n\s\w()',`]*)(primary key)\s*\(`([\w\-_]*)`\).*\n.*engine\s*=\s*(InnoDB).*charset\s*=\s*([\w\-]*);

将所有关键信息分组,稍后再处理。
[Regex Demo]

但是我无法对每一个字段信息进行分组,可能是顺序的原因, 有人可以修复那个正则表达式,或者教我一些线索吗?

Note: I should note that it is not so good to do everything by regex.
Note: You can use multiple steps to validate a string by regex.

所以,我能想到的开始使用正则表达式可以是:

第 1 步:检查整个创建命令:

"^\s*create\s+table\s*`([a-z]\w+)`\s*\(([\s\S]+)\)\s*
 engine\s*=\s*innodb\s+
 charset\s*=\s*utf8mb4\s+
 comment\s'[^']+'\s*;\s*$
"giu

 = name of table
 = body of create statement

[Regex Demo]

第 2 步:检查创建命令的主体结构 - 从 </code> -:</p> <pre><code>"([\s\S]+)\s* primary\s+key\s*\(\s*`([a-z]\w*)`\s*\)\s* (,\s*unique\s+key\s+uniq_\w+\s*\(`([a-z]\w*)`\))? (,\s*key\s+idx_\w+\s*\((\s*,?\s*`([a-z]\w*)`\s*)+\)\s*)+ "giu = fields info = primary key field name = unique key field name = keys field name

[Regex Demo]

第 3 步:检查字段信息

"(`([a-z]\w*)`\s+
 (timestamp|(tiny|small|)int(\s+\(\s*\d+\s*\))?(\s+unsigned)?|varchar\s*\(\d+\)|decimal\s*\(\s*\d+\s*,\s*\d+\s*\)))\s+
 not\s+null\s+
 (auto_increment|default\s+('[^']*'|current_timestamp))\s+
 comment\s+'[^']+',
"giu

 = fields name

[Regex Demo]

步骤 4:检查 步骤 2 的字段名称与 步骤 3
的字段名称 并使用以下正则表达式的 </code> 检查 <em> 步骤 2</em> 的主键字段名称:</p> <pre><code>" `([a-z]\w)*`.+auto_increment "giu

[Regex Demo]


如果您想要任何类型的 engine 部分和 charset 部分,您的正则表达式将更改为:

^\s*create\s+table\s*`([a-z]\w+)`\s*\(([\s\S]+)\)\s*
 ((engine\s*=\s*innodb\s+)(charset\s*=\s*utf8mb4\s+)?|(charset\s*=\s*utf8mb4\s+)(engine\s*=\s*innodb\s+)?)?
 comment\s'[^']+'\s*;\s*
$

[Regex Demo]

HTH