如何使用正则表达式查找连接条件中使用的表名和列?
从表 1 中选择 * 左外连接表 2 在 table1.column1 = table2.column1
上结果 = 表名 专栏 1
我需要正在工作的正则表达式是雪花。
我使用 PHP 的 PCRE 引擎编写了这个正则表达式(使用反向引用和带注释的扩展符号):
https://regex101.com/r/x99nHu/2
正则表达式:
\bJOIN\s+ # JOIN keyword + spaces.
`?(?<table>\w+)`?\s+ # Capture table name in group n°1 + spaces
(?:AS\s+`?(?<alias>\w+)`?\s+)? # Optional alias (captured in group n°2).
ON\s+ # ON keyword + spaces.
.*? # Ungreedy match everything because we don't
# know in wich order the ON condition is written.
`?(?:\k<table>|\k<alias>)`?\. # Table name or alias + dot.
`?(\w+)\`? # Table field.
我正在使用以下标志:
我还考虑了一个可选的表别名(这很常见)。
\k<table>
和
\k<alias>
是对
捕获上面创建的组。解释:
\bJOIN\s+
匹配单词的开头,然后是单词“JOIN” 后跟一个或几个空格、制表符或换行符。
`?
匹配可选的反引号。
(?<table>\w+)
会将一个词捕获到名为“table”的组中。
中间的.*?
是用不贪婪的方式匹配任何东西。和我们一样 不知道ON条件会怎么写,要跳过 在我们将表名或别名与其匹配之前的可能条件 字段名称。
(?:\k<table>|\k<alias>)
是一个非捕获组来匹配 表名或其别名。
而不是 PCRE 引擎对其进行测试,但您会注意到它的反应并不完全相同并且 没有在查询一中提供正确的字段名称,其中没有别名 给出并且条件从主要暴露字段的位置 先表。我特别更改了字段名称,以便您可以看到 它也是:
// The regular expression written in JavaScript syntax (extended doesn't exist).
const regex = /\bJOIN\s+`?(?<table>\w+)`?\s+(?:AS\s+`?(?<alias>\w+)`?\s+)?ON\s+.*?`?(?:\k<table>|\k<alias>)`?\.`?(\w+)\`?/gis;
document.addEventListener("DOMContentLoaded", () => {
let findButton = document.getElementById('find');
let resultsDiv = document.getElementById('results');
findButton.addEventListener('click', (e) => {
let sql = document.getElementById("sql").value;
let match;
let results = [];
resultsDiv.innerHTML = ''; // Clear the output.
while ((match = regex.exec(sql)) !== null) {
let result = `Table: <code>${match[1]}</code>`;
if (match[2] !== undefined) {
result += ` (aliased by <code>${match[2]}</code>)`;
}
result += `, field: <code>${match[3]}</code>`;
results.push(result);
}
if (results.length) {
let ul = document.createElement('ul');
resultsDiv.appendChild(ul);
results.forEach((result, i) => {
let li = document.createElement('li');
li.innerHTML = result;
ul.appendChild(li);
});
} else {
let p = document.createElement('p');
p.classList.add('error');
p.innerHTML = 'No results found!';
resultsDiv.appendChild(p);
}
e.preventDefault();
});
});
html {
font: 16px/1.4 Arial, sans-serif;
}
html, body {
min-height: 40em;
}
code {
border: 1px solid silver;
background: #f8f8f8;
padding: 0 .3em;
border-radius: .2em;
}
.error {
color: darkred;
}
<form action="#">
<div>
<label for="sql">SQL query:</label><br>
<textarea name="sql" id="sql" cols="64" rows="30">select *
from table1
left outer join table_name
on table1.column_main_table = table_name.column_join_table;
SELECT
u.`first_name`, u.`last_name`, m.`title`
FROM
`users` AS u
INNER JOIN
`movies` AS m
ON m.`id` = u.`movie_id`;
SELECT
m.`type`, u.`genre`
FROM
`movies` AS m
LEFT JOIN
`users` AS u
ON u.`movie_id` = m.`id`
GROUP BY
m.`type`;
SELECT u.`first_name`, u.`last_name`, `movies`.`title`
FROM `users` AS u
RIGHT JOIN `movies`
ON `movies`.`id` = u.`movie_id`
WHERE `movies`.`id` > 100;</textarea>
</div>
<button id="find">Find the join table and field</button>
<div id="results">
</div>
</form>
PCRE、Java 和 .NET 引擎的行为与我们希望的一样。所以 对于 JavaScript,我们可能必须更改正则表达式,但我不知道如何更改。
const tableName = match[1].split('.').pop();
const aliasName = match[3];
const joinCondition = match[4];
const columnRegex = new RegExp(`\\b${aliasName}\\.(\\w+)\\b`, 'g');
const columns = [];
let columnMatch = null;
while ((columnMatch = columnRegex.exec(joinCondition)) !== null) {
columns.push(columnMatch[1]);
}
return { tableName, aliasName, columns };
}
return extractJoinDetails(查询); $$;
CALL extractJoinDetails('SELECT * FROM table1 LEFT OUTER JOIN schema.table2 AS 别名 ON table1.id = alias.id WHERE alias.name = ''John Doe''');