如何在 Access 中解析 SQL 查询以获取该查询中涉及的 table 名称
How to parse SQL query to get table names involved in that query in Access
我决定使用 vba 和正则表达式来解决这个问题。这是部分代码:
Dim strPattern As String: strPattern = "(FROM|JOIN|from|From|Join|join)\s+([^ ,]+)(?:\s*,\s*([^ ,]+))*\s*"
Dim strReplace As String: strReplace = ""
Dim regEx As New RegExp
Dim strInput As String
Set MyMatches = regEx.Execute(Form)
If MyMatches.Count <> 0 Then
With MyMatches
For myMatchCt = 0 To MyMatches.Count - 1
If Left(MyMatches.Item(myMatchCt), 6) <> "FROM (" And Left(MyMatches.Item(myMatchCt), 6) <> "JOIN (" Then
str = MyMatches.Item(myMatchCt)
lenght = Len(str)
format_data = Right(str, lenght - 4)
pos = InStr(format_data, ")") + InStr(format_data, "(select")
If pos = 0 Then
rst.AddNew
rst!block_id = rs("block_id")
rst!trans_table = format_data
rst.Update
End If
End If
Next
End With
End if
已解析的表被写入 rst
。
它几乎可以很好地处理许多类型的查询,我只对 select
查询感兴趣。但是我不知道如何处理子查询,例如从这个查询中我得到奇括号 (
:
select *
from (
select * from t1
union
select * from t2
) t
where 1=1;
那么这里有什么问题?
乍一看...
Left(MyMatches.Item(myMatchCt), 6) <> "FROM ("
<> 区分大小写
也就是说这是真的
左("From (", 6) <> "FROM ("
您需要将其更改为
Ucase(Left(MyMatches.Item(myMatchCt), 6)) <> "FROM ("
与"JOIN"条件类似
我明白你为什么要编写自己的代码,因为购买 SQL 解析器很贵!
这是我找到的关于此的一些文本和链接:
另请参阅此 SO 问题:here 其中指出:
RegEx 不太擅长这个,因为它比看起来要复杂得多:
如果他们使用 LEFT/RIGHT INNER/OUTER/CROSS/MERGE/NATURAL 连接而不是 a,b 语法怎么办?无论如何都应该避免使用 a,b 语法。
嵌套查询呢?
如果没有table怎么办(选择常量)
换行符和其他空格格式呢?
别名?
我可以继续。
您可以做的是寻找 sql 解析器,然后 运行 通过它进行查询。
另请注意:
您想要访问 SQL 查询的任意子结构(包括子 SELECT)?您需要的是 SQL 感兴趣方言的完整解析器。
尝试here
This one 将花费您 400 美元!我开始明白你为什么要写一个了 - 顺便说一句很好。
SQL 是一种相当庞大和复杂的语言。可以手动编写递归下降解析器来执行此操作,但这需要大量工作。使用解析器生成器和 SQL BNF 来提供它可能会更好。
我决定使用 vba 和正则表达式来解决这个问题。这是部分代码:
Dim strPattern As String: strPattern = "(FROM|JOIN|from|From|Join|join)\s+([^ ,]+)(?:\s*,\s*([^ ,]+))*\s*"
Dim strReplace As String: strReplace = ""
Dim regEx As New RegExp
Dim strInput As String
Set MyMatches = regEx.Execute(Form)
If MyMatches.Count <> 0 Then
With MyMatches
For myMatchCt = 0 To MyMatches.Count - 1
If Left(MyMatches.Item(myMatchCt), 6) <> "FROM (" And Left(MyMatches.Item(myMatchCt), 6) <> "JOIN (" Then
str = MyMatches.Item(myMatchCt)
lenght = Len(str)
format_data = Right(str, lenght - 4)
pos = InStr(format_data, ")") + InStr(format_data, "(select")
If pos = 0 Then
rst.AddNew
rst!block_id = rs("block_id")
rst!trans_table = format_data
rst.Update
End If
End If
Next
End With
End if
已解析的表被写入 rst
。
它几乎可以很好地处理许多类型的查询,我只对 select
查询感兴趣。但是我不知道如何处理子查询,例如从这个查询中我得到奇括号 (
:
select *
from (
select * from t1
union
select * from t2
) t
where 1=1;
那么这里有什么问题?
乍一看...
Left(MyMatches.Item(myMatchCt), 6) <> "FROM ("
<> 区分大小写
也就是说这是真的 左("From (", 6) <> "FROM ("
您需要将其更改为
Ucase(Left(MyMatches.Item(myMatchCt), 6)) <> "FROM ("
与"JOIN"条件类似
我明白你为什么要编写自己的代码,因为购买 SQL 解析器很贵!
这是我找到的关于此的一些文本和链接:
另请参阅此 SO 问题:here 其中指出:
RegEx 不太擅长这个,因为它比看起来要复杂得多:
如果他们使用 LEFT/RIGHT INNER/OUTER/CROSS/MERGE/NATURAL 连接而不是 a,b 语法怎么办?无论如何都应该避免使用 a,b 语法。 嵌套查询呢? 如果没有table怎么办(选择常量) 换行符和其他空格格式呢? 别名? 我可以继续。
您可以做的是寻找 sql 解析器,然后 运行 通过它进行查询。
另请注意: 您想要访问 SQL 查询的任意子结构(包括子 SELECT)?您需要的是 SQL 感兴趣方言的完整解析器。
尝试here
This one 将花费您 400 美元!我开始明白你为什么要写一个了 - 顺便说一句很好。
SQL 是一种相当庞大和复杂的语言。可以手动编写递归下降解析器来执行此操作,但这需要大量工作。使用解析器生成器和 SQL BNF 来提供它可能会更好。