查询 SQL 中的感叹号

Posted

技术标签:

【中文标题】查询 SQL 中的感叹号【英文标题】:Exclamation Marks in a Query SQL 【发布时间】:2010-05-18 17:24:22 【问题描述】:

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

[FETT List]![FETT Search]
    FETT 列表是一个表格 FETT 搜索是 FETT 列表中的一列

谁能解释一下感叹号是什么意思?

谢谢

【问题讨论】:

请在您的问题中添加适当的标签。我添加了ms-access,因为我相信这是在 Access 中,但我可能错了。请确保没问题。 这个问题没有 2007 版特定的内容,所以说真的, ms-access 是一个足够的标签(尽管有人可能会在问题中提到 2007 版)。 【参考方案1】:

嗯,你每天都会学到新东西!

我本来打算解释一下,如果你说引用是[Forms]![FETT List]![FETT Search],那么解释起来就容易了,作为对[FETT Search]控件的引用在 [FETT 列表] 表格上。但如果没有父集合(表单报告),它在 SQL 语句中的任何上下文中看起来都不是有效的引用。

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

  SELECT [tblCustomer]![LastName] AS LastName 
  FROM tblCustomer;

在 Access 中,这 100% 等同于这条 SQL 语句:

  SELECT tblCustomer.LastName 
  FROM tblCustomer;

……所以我不明白为什么有人会写它,除非他们忘记了上下文(或者一开始就没有理解它)。这可能是别名出错的情况,但这不是我认为好的形式。

现在,关于!(砰)与.(点)的一般性问题的长答案:

通常,在 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

此外,在 VBA 代码中,Microsoft 设计了一些东西来混淆表单和报告中的这种区别,过去 Me!MyFavoriteControl 作为控件引用是合法的,而 Me.MyFavoriteControl 仅作为引用是合法的到自定义属性(或模块级变量,它将是对象的成员)。您还可能不明智地命名一个函数或子“MyFavoriteControl”,并且可以使用点运算符来引用它。

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

  Debug.Print Me.Control1

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

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

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

    您依赖于 VBA 的隐式行为及其编译。虽然这通常是一件好事(特别是如果您照顾好您的代码),VBA compilation is very complex and subject to corruption。多年来,有经验的开发人员报告说,使用点运算符会使代码更容易损坏,因为它添加了另一层隐藏代码,可能与您可以的应用程序部分不同步> 明确改变。

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

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

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

有些人争辩说他们不能放弃 Intellisense,但是当你使用 bang 运算符时,你完全放弃它是不正确的。是的,您放弃了“真正智能”的 Intellisense,即将 Intellisense 列表限制为所选对象的方法/属性/成员的版本,但我不需要它——我需要 Intellisense 来保存击键,并且使用 Ctrl+SPACEBAR 可以获得完整的 Intellisense 列表,该列表会像特定于上下文的 Intellisense 一样自动完成,然后可以使输入短路。

点/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

如果您牢记您在哪个命名空间中工作,那就不会那么混乱了——点用于 SQL 语句,而 bang 用于 DAO 代码。

所以,总结一下:

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

    在表单和报表中,您可以将 bang 运算符用于控件,将点运算符用于属性/方法(虽然您也可以使用点运算符,但不一定可取)。

    在 VBA 代码中,对表单和报表上的控件的引用可以使用点或 bang,尽管点可能容易导致代码损坏。

    在 SQL 中,您可能会看到使用了 bang 运算符,但前提是在 Access 表单或报表上引用了“Form!FormName!ControlName”或“Report!ReportName!ControlName”形式的控件。

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

这对你来说够复杂吗?

【讨论】:

这是我在 SO 上见过的最长的答案 我写的比这长得多!【参考方案2】:

通常您会在 MS Access 代码中看到这一点(感叹号,SQL 服务器的句号)。您可以通过 table.column 引用列,或者如果您给表一个别名,那么通过 alias.column。如果您想在使用联接时具体化,则可以这样做,或者当查询/联接中的两个(或更多)表在每个表中具有相同的列名时,您可能必须这样做。

【讨论】:

该!是在 Access 中指定 SQL 语句中的字段的非标准方式。它已被处理,但现在很好,因为 [Table]![Field] 在 QBE 中被分配了一个即时别名,而 Table.Field 将继承字段名(即没有别名)。【参考方案3】:

我认为esclamation标记只是一个常规的分隔符。

在 Oracle PL/SQL 中,您使用点:

[FETT 列表].[FETT 搜索]

还有其他线索吗?!

【讨论】:

Oracle 是否允许在表/列的名称中使用空格?我认为在 Oracle 中可能是 FETT_List.FETT_Search 是的,Oracle 允许在表名或列名中使用空格,但是您必须将整个字符串括在引号之间,如下例所示:CREATE TABLE goofy ("my column" VARCHAR2 (1000)); 请注意单词 和单词 之间的空格 另一个例子:CREATE TABLE "super mario land" ("my column" VARCHAR2 (1000)); 在 Jet/ACE SQL 中,括号用于包含空格或非常规字符的字段。这 !是非标准用法,尽管 Access 适应非标准并半正确地解释它。

以上是关于查询 SQL 中的感叹号的主要内容,如果未能解决你的问题,请参考以下文章

C语言中的感叹号是怎么用的

AS400 - 令牌“!”无效

数据库部署之导入的视图数量少于脚本中的视图函数/存储过程导入完毕存在大红叹号问题原因及解决方法

Java的方法参数中的双感叹号和#号是啥意思?

Javascript中的感叹号和函数function

类型定义中的感叹号