我一直在使用 VBA 检查我的 Access 2000 数据库中的所有查询、表单和模块,但它可能非常乏味和缓慢。最近,我决定仔细研究一下 Access 中的系统表,特别是 MSysQueries 和 MSysObjects。我可以使用这些表更快地检查数据库中的对象吗?当然,这些表是只读的,所以我不能通过它们对数据库进行任何修改而不返回VBA。MSysQueries 中的属性是什么意思?
4 回答
好吧,我在 Google 群组上看到了这篇文章。我对自己的表格进行了进一步调查,并希望分享一张我在已完成工作的启发下创建的信息表格。
每个查询可以占用表中的多行。
属性为 0 的行是查询的开始。
属性为 1 的行表示查询的类型。
- 标志值 1 = SELECT 查询。
- 标志值 2 = SELECT ... INTO 查询或生成表查询。Name1 将具有创建的表的名称。
- 标志值 3 = INSERT 查询;Name1 将具有要插入的表的名称。
- 标志值 4 = UPDATE 查询
- 标志值 5 = DELETE 查询
- 标志值 6 = 交叉表查询 (TRANSFORM)
- 标志值 9 = UNION 查询
具有属性 2 的行(可能有多个)是查询的每个形式参数。Flag 列表示数据类型(即 dbText 的“10”),Name1 列表示参数的名称。如果没有属性为 2 的行,则查询没有形式参数。
具有属性 3 的行表示存在 UNION 或 DISTINCT 关键字。
- 标志值 0 = 没什么特别的
- 标志值 1 = UNION ALL
- 标志值 2 = SELECT DISTINCT
- 标志值 3 = UNION
- 标志值 8 = SELECT DISTINCTROW
- 标志值 9 = 对主字段和子字段的查询
具有属性 4 的行指示查询是否来自外部数据库。如果属性 4 存在,Name1 将包含源。
具有属性 5 的行(可能有多个)表示在查询中找到的每个表。如果查询是 UNION 查询,Expression 字段在 UNION 关键字上有一个拆分,Name2 字段有一个系统生成的表别名。对于查询中的所有其他表,Name1 是表的名称,Name2 是别名(如果有的话)。
具有属性 6 的行(可能有多个)表示查询中的每个字段或表达式。如果查询没有属性 6,则假定行为是包含所有字段。Expression 字段包含每个字段表达式或名称,Name1 包含字段别名(如果有)。
- 标志值 0 = 字段或表达式的值
- 标志值 1 = 该字段是交叉表查询中的列标题。
- 标志值 2 = 该字段是交叉表查询中的行标题。
具有属性 7 的行(可能有多个)表示每个单独的连接“ON”表达式。Expression 字段包含实际的连接表达式。Name1 包含连接中的第一个表。Name2 包含连接中的第二个表。
- 标志值 1 = 内连接
- 标志值 2 = 左连接
- 标志值 3 = 右连接
具有属性 8 的行包含 Expression 字段中的整个 WHERE 子句。如果没有 where 子句,则从查询中省略属性 8。
具有属性 9 的行(可能有多个)表示查询的 GROUP BY 子句中的每个单独的 Group By 表达式。表达式字段按表达式包含每个组。
- 标志值 0 = 字段或表达式的值
- 标志值 1 = 该字段是交叉表查询中的列标题。
- 标志值 2 = 该字段是交叉表查询中的行标题。
具有属性 11 的行(可能有多个)表示查询的 ORDER BY 子句中的每个单个 Order By 表达式。表达式字段包含每个表达式的顺序。Name1 有“D”或“d”表示排序是按降序进行的。
属性为 255 的行是查询的结尾。
我不完全确定 Order 字段的作用,但我确实发现它不是 Null,虽然它有时具有空字符串的值,但它并不总是具有该值。空字符串出现在属性 5、6、7 和 9 上,但这些属性并不总是空字符串。
感谢@Bobort 的精彩解释,我能够创建一个查询,列出当前数据库中的所有查询,包括它们的输入表/查询、查询类型和目标表(用于操作查询)。
我想我可以在这里分享。
SELECT MSysObjects.Name AS queryName,
Mid("SelectMakTblAppendUpdateDeleteXtab 777777PassThUnion ",([msysqueries]![Flag]-1)*6+1,6) AS queryType,
src.Name1 AS [Input],
MSysQueries.Name1 AS Target
FROM (MSysQueries INNER JOIN MSysObjects ON MSysQueries.ObjectId = MSysObjects.Id)
LEFT JOIN (select * from MSysQueries WHERE Attribute = 5 ) AS src
ON MSysQueries.ObjectId = src.ObjectId
WHERE (((MSysObjects.Name)>"~z") AND ((MSysQueries.Attribute) =1))
ORDER BY MSysObjects.Name, src.Name1;
要使用,只需在 SQL 视图中创建一个查询并粘贴上面的代码。
除了 Bobort 和 iDevlop 的回答:
属性为 1 的行表示查询的类型。
- 标志值 7 = DDL 查询(例如
CREATE TABLE...
) - 标志值 9 = 通过查询
具有属性 3 的行表示谓词。
- 标志值 1 = 所有值,或 UNION ALL(如果是 UNION 查询)
- 标志值 4 = WITH OWNERACCESS OPTION
- 标志值 16 = TOP N
- 标志值 48 = TOP N PERCENT
具有属性 5 的行(可能有多个)表示在查询中找到的每个FROM表/查询
- 表达式包含 FROM 源,如果是 UNION 查询,则包含 SELECT 语句
属性为 10 的行包含 Expression 字段中的整个 HAVING 子句。如果没有 HAVING 子句,则从查询中省略属性 10。
该Order
字段是一个包含 4 个字节数组的 BIG-ENDIAN 二进制值(二进制字段可以使用 VBA 添加,但不能使用 UI 添加,除非您从系统表中的二进制字段复制和粘贴。)但是,在大多数数据库中,在MSysQueries
表中,您不太可能遇到大于 255 的二进制值,因此您可以通过检查索引 3 处的字节来快速转换为字节。例如:
Sub EnumOrder()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset( _
" SELECT * FROM MSysQueries " & _
" WHERE Attribute = 6 " & _
"ORDER BY ObjectId Asc, [Order] Asc")
With rst
Do While Not .EOF
Debug.Print .Fields("ObjectId"), .Fields("Order")(3)
.MoveNext
Loop
.Close
End With
End Sub
属性 3 出现累积值。因此其他项目包括:
- 标志 12 SELECT DISTINCT.... 带有 OWNERACCESS 选项
- 标志 18 SELECT DISTINCT TOP(即 2+16)
- 标志 24 SELECT DISTINCTROW TOP(即 8+16)
- 标志 50 SELECT DISTINCT TOP PERCENT(即 2+48)
- 标志 56 SELECT DISTINCTROW TOP PERCENT(即 8+48)
我写了一篇关于 MSysQueries 表工作原理的扩展文章。请参阅Access 如何存储查询。