正则表达式查找连接条件中使用的表名和连接条件中使用的列

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

如何使用正则表达式查找连接条件中使用的表名和列?

从表 1 中选择 * 左外连接表 2 在 table1.column1 = table2.column1

结果 = 表名 专栏 1

我需要正在工作的正则表达式是雪花。

sql regex decoding regexp-replace snowflake-schema
2个回答
0
投票

我使用 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.

我正在使用以下标志:

  • g 用于 g 全局匹配(也许不适合您的情况。这取决于 如果您有多个 JOIN 语句)。
  • i 对于案例 insensitive.
  • s 使点也匹配新行(因为 ON 条件可以 写在几行)。
  • x 用于扩展语法(允许注释和忽略空格)。
  • 我考虑到 SQL 查询可以用 表格、别名或字段名称周围的反引号。

我还考虑了一个可选的表别名(这很常见)。

\k<table>

\k<alias>
是对 捕获上面创建的组。
解释:

  • \bJOIN\s+

    匹配单词的开头,然后是单词“JOIN” 后跟一个或几个空格、制表符或换行符。

    
    

  • `?

    匹配可选的反引号。

    
    

  • (?<table>\w+)

    会将一个词捕获到名为“table”的组中。

    
    中间的

  • .*?

    是用不贪婪的方式匹配任何东西。和我们一样 不知道ON条件会怎么写,要跳过 在我们将表名或别名与其匹配之前的可能条件 字段名称。

    
    

  • (?:\k<table>|\k<alias>)

    是一个非捕获组来匹配 表名或其别名。

    
    

  • 您也可以在此处使用
JavaScript

而不是 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,我们可能必须更改正则表达式,但我不知道如何更改。


0
投票

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''');

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