使用 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 使用一些规范来捕捉这个语句
- 字段必须有
COMMENT
- 必须有
PRIMARY KEY
,PRIMARY KEY
必须有AUTO_INCREMENT
- 每个字段必须有
DEFAULT
值
ENGINE
必须是 INNODB
charset
必须是 utf8mb4
我使用的正则表达式模式如下:
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
第 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
第 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
步骤 4:检查 步骤 2 的字段名称与 步骤 3
的字段名称
并使用以下正则表达式的 </code> 检查 <em> 步骤 2</em> 的主键字段名称:</p>
<pre><code>"
`([a-z]\w)*`.+auto_increment
"giu
如果您想要任何类型的 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*
$
HTH
最近有一项任务是解析 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 使用一些规范来捕捉这个语句
- 字段必须有
COMMENT
- 必须有
PRIMARY KEY
,PRIMARY KEY
必须有AUTO_INCREMENT
- 每个字段必须有
DEFAULT
值 ENGINE
必须是INNODB
charset
必须是utf8mb4
我使用的正则表达式模式如下:
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
第 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
第 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
步骤 4:检查 步骤 2 的字段名称与 步骤 3
的字段名称
并使用以下正则表达式的 </code> 检查 <em> 步骤 2</em> 的主键字段名称:</p>
<pre><code>"
`([a-z]\w)*`.+auto_increment
"giu
如果您想要任何类型的 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*
$
HTH