查询SQL中的感叹号

Chi*_*ghE 14 sql ms-access-2007

我正在阅读这个查询,我遇到了一条我不明白的线路

[FETT List]![FETT Search]
Run Code Online (Sandbox Code Playgroud)
  1. FETT List是一个表
  2. FETT Search是FETT列表中的一列

有人可以解释感叹号的含义吗?

谢谢

Dav*_*ton 19

好吧,你每天都学到新东西!

我原本打算解释,如果你说的是参考[窗体]![FETT列表]![FETT搜索],那么这将是很容易解释,作为参考[FETT搜索]器上的[ FETT List]表格.但是如果没有父集合(Forms of Forms),它在SQL语句中的任何上下文中看起来都不是有效的引用.

但后来我想测试它,并发现(令我惊讶的是)这个SQL语句在Access表单中被视为有效:

  SELECT [tblCustomer]![LastName] AS LastName 
  FROM tblCustomer;
Run Code Online (Sandbox Code Playgroud)

在Access中,这与此SQL语句完全等效:

  SELECT tblCustomer.LastName 
  FROM tblCustomer;
Run Code Online (Sandbox Code Playgroud)

...所以我不明白为什么有人会写它,除非他们忘记了背景(或者从一开始就不理解它).这可能是走样错误的情况,但这不是我认为好的形式.

现在,对一般问题的答案很长!(爆炸)vs. (点):

通常,在Access中,bang运算符描述对象及其项的默认集合.点运算符描绘对象及其方法,属性和成员.

这适用于Access,适用于Access对象和Access的对象模型.

但是您也在Access中使用SQL,因此在SQL中也有TableName.FieldName,其中点运算符分隔默认集合中的项.TableName.FieldName可以被认为是TableName.Fields("FieldName")的缩写,正如您在Forms中找到的那样!MyForm!MyControl等同于Forms!MyForm.Controls("MyControl").但是这条规则不适用于SQL - TableName.Fields("FieldName")是无效的SQL,只有TableName.FieldName是.

因此,您必须直截了当地控制您正在使用的命名空间,即,它是Access命名空间还是SQL命名空间.

Forms!MyForm也等同于Forms.Item("MyForm"),因此超长形式将是Forms.Items("MyForm").Controls("MyControl").请注意,bang运算符是带有点运算符的较长格式版本的快捷方式,因此bang运算符经常被使用,优先于点运算符.另请注意,当您需要引用名称存储在变量中的项目时,最终会使用较长的表单,这对于bang运算符是不可能的:

  Dim strForm As String

  strForm = "MyForm"
  ' This is OK
  Debug.Print Forms(strForm).Controls.Count
  ' This is not
  Debug.Print Forms!strForm.Controls.Count
Run Code Online (Sandbox Code Playgroud)

此外,在VBA代码中,Microsoft已经设计了一些东西来混淆Forms和Reports中的这种区别,以前它就是Me!MyFavoriteControl合法作为控件引用,而Me.MyFavoriteControl仅作为对自定义的引用是合法的property(或模块级变量,它将是对象的成员).你也可以不明智地命名一个函数或子"MyFavoriteControl",它可以用点运算符引用.

但随着VBA的引入,MS在所有控件周围引入了隐式创建(和维护)的隐藏属性包装器,以便您可以使用点运算符.这有一个巨大的优势,那就是控制引用的编译时检查.也就是说,如果您键入Me.MyFavoriteControl并且没有该名称的控件,并且在表单/报表的命名空间中没有任何具有该名称的其他成员,那么您将收到编译时错误(实际上,您将是一旦你离开了你犯了错误的代码行,就会通知错误.所以,如果你有这个代码:

  Debug.Print Me.Control1
Run Code Online (Sandbox Code Playgroud)

...并且您将Control1重命名为MyControl,下次编译代码时会出现错误.

什么可能是编译时检查的缺点?好吧,有几件事:

  1. 代码变得更难以让程序员在视线中理解.在过去,Me!Reference是表单/报表的默认集合中的一个项目(它是Fields和Controls集合的联合).但是Me.Reference可以是一个控件或一个字段或一个自定义属性或一个公共模块级变量或一个公共子/函数,或者,或者......因此,它牺牲了直接的代码可理解性.

  2. 您依赖于VBA的隐式行为及其编译.虽然这通常是一件好事(特别是如果你好好照顾你的代码),VBA编译非常复杂并且容易腐败.多年来,经验丰富的开发人员报告说,使用点运算符会使代码更容易受到损坏,因为它会添加另一层隐藏代码,这些代码可能与您可以显式更改的应用程序部分不同步.

  3. 因为你无法控制那些隐式属性包装器,当它们出错时,你必须从头开始重新创建你的模块承载对象(通常SaveAsText足以清除损坏而不会丢失任何东西).

因此,许多有经验的开发人员(包括我自己)不使用点运算符来控制表单/报表.

如果您使用一组标准的命名约定,这并不是一些人可能会想到的牺牲.例如,对于表单上的绑定控件,让它们使用默认名称(即控件绑定的字段的名称).如果我没有在代码中引用控件,我永远不会更改其名称.但是我第一次在代码中引用它时,我更改了它的名称,以便控件名称与它所绑定的字段的名称不同(这种消歧在某些情况下是至关重要的).因此,当我决定在代码中引用它时,名为MyField的文本框变为txtMyField.我编写代码后唯一一次更改字段名称是因为我以某种方式确定该字段名称错误.在这种情况下,查找/替换很容易.

有些人认为他们不能放弃智能感知,但是当你使用爆炸操作员时,你完全放弃它并不是真的.是的,你放弃了"真正智能"的智能感知,即将智能感知列表限制为所选对象的方法/属性/成员的版本,但我不需要它 - 我需要智能感知来节省击键,使用Ctrl-SPACEBAR,您将获得一个完整的智能感知列表,该列表可以像上下文特定的智能感知一样自动填充,然后可以使输入短路.

dot/bang混淆的另一个方面是VBA代码中的DAO记录集,其中您使用点运算符作为用于打开记录集的SQL,并使用bang运算符来引用结果记录集中的字段:

  Dim rs As DAO.Recordset

  Set rs = CurrentDB.OpenRecordset("SELECT MyTable.MyField FROM MyTable;")
  rs.MoveFirst
  Debug.Print rs!MyField

  rs.Close
  Set rs = Nothing
Run Code Online (Sandbox Code Playgroud)

如果你记住你正在使用哪个命名空间,这不是那么令人困惑 - 在SQL语句中使用点和在DAO代码中使用.

所以,总结一下:

  1. 在SQL中,您对表中的字段使用点运算符.

  2. 在表单和报表中,您使用bang运算符作为控件,使用点运算符作为属性/方法(尽管您也可以使用点运算符,但不一定是可取的).

  3. 在VBA代码中,对表单和报表上的控件的引用可以使用点或砰,但点可能容易出现代码损坏.

  4. 在SQL中,您可能会看到使用了bang运算符,但只有在Access窗体或报表上有对"Form!FormName!ControlName"或"Report!ReportName!ControlName"形式的控件的引用时才会使用.

  5. 在使用DAO记录集的VBA代码中,您可以看到dot和bang运算符,前者用于定义用于打开记录集的SQL,后者用于在结果记录集打开时引用结果记录集中的字段.

这对你来说足够复杂吗?

  • 这是我在 SO 上见过的最长的答案 (2认同)
  • 我的写作时间比这长得多! (2认同)

Thy*_*ine 10

通常,您在MS Access代码中看到此信息(对于感叹号,SQL服务器的句点).您可以通过table.column引用列,或者如果为表提供别名,则通过alias.column引用.如果要在使用连接时特定,可以执行此操作,或者当查询/连接中的两个(或更多)表在每个表中具有相同的列名时,可能必须执行此操作.

  • 的!是一种在Access中的SQL语句中指定字段的非标准方法.它已被处理,但现在好了,因为[Table]![Field]在QBE中被分配了一个动态别名,而Table.Field将继承字段名(即没有别名). (2认同)