MS Access(Jet/ACE)中的无表UNION查询

mwo*_*e02 26 sql ms-access jet

这按预期工作:

SELECT "Mike" AS FName
Run Code Online (Sandbox Code Playgroud)

这失败,错误"查询输入必须包含至少一个表或查询":

SELECT "Mike" AS FName
UNION ALL
SELECT "John" AS FName
Run Code Online (Sandbox Code Playgroud)

这只是Jet/ACE数据库引擎的怪癖/限制还是我遗漏了什么?

Han*_*sUp 24

你没有忽视任何事情.访问'数据库引擎将允许SELECT没有FROM数据源的单行.但是,如果你想UNIONUNION ALL多个行,你必须包括一个FROM......即使你不是从数据源中引用的任何字段.

我创建了一个包含一行的表,并添加了一个检查约束,以确保它始终只有一行.

Public Sub CreateDualTable()
    Dim strSql As String
    strSql = "CREATE TABLE Dual (id COUNTER CONSTRAINT pkey PRIMARY KEY);"
    Debug.Print strSql
    CurrentProject.Connection.Execute strSql
    strSql = "INSERT INTO Dual (id) VALUES (1);"
    Debug.Print strSql
    CurrentProject.Connection.Execute strSql

    strSql = "ALTER TABLE Dual" & vbNewLine & _
        vbTab & "ADD CONSTRAINT there_can_be_only_one" & vbNewLine & _
        vbTab & "CHECK (" & vbNewLine & _
        vbTab & vbTab & "(SELECT Count(*) FROM Dual) = 1" & vbNewLine & _
        vbTab & vbTab & ");"
    Debug.Print strSql
    CurrentProject.Connection.Execute strSql
End Sub
Run Code Online (Sandbox Code Playgroud)

Dual表对于诸如此类的查询非常有用:

SELECT "foo" AS my_text
FROM Dual
UNION ALL
SELECT "bar"
FROM Dual;
Run Code Online (Sandbox Code Playgroud)

我见过的另一种方法是使用带有一个SELECT语句TOP 1或一个WHERE将结果集限制为单行的子句.

注意检查约束是使用Jet 4添加的,仅适用于从ADO执行的语句.CurrentProject.Connection.Execute strSql因为CurrentProject.Connection是ADO对象而起作用.如果您尝试使用DAO(即CurrentDb.Execute或从Access查询设计器)执行相同的语句,您将收到语法错误,因为DAO无法创建检查约束.

  • @GordThompson如果我指出错误,请纠正我:你的设计允许不超过一行,但也允许删除一行.我想保证`Dual`总是只包含一行. (2认同)

Luk*_*der 6

如果您有权访问某些系统表,则可以通过以下方式模拟双重表:

(SELECT COUNT(*) FROM MSysResources) AS DUAL
Run Code Online (Sandbox Code Playgroud)

不幸的是,我不知道任何系统表...

  • 总是可用的,可读的(并非每个连接都可以访问MSysObjects)
  • 仅包含一条记录,例如Oracle DUAL或DB2的记录SYSIBM.DUAL

所以你会写:

SELECT 'Mike' AS FName
FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL
UNION ALL
SELECT 'John' AS FName
FROM (SELECT COUNT(*) FROM MSysResources) AS DUAL
Run Code Online (Sandbox Code Playgroud)

例如,这就是在jOOQ中实现为语法元素的内容

  • 我喜欢这个主意。如果您知道任何可用系统表的名称,您可以执行类似“FROM (SELECT TOP 1 NULL FROM MSysResources) A​​S DUAL”之类的操作。“TOP 1”限制为 1 行,“NULL”是单个值返回 - 它消除了知道任何列名称的需要。您只需要一个表名。 (2认同)

Cri*_* S. 5

当您对数据库的只读访问权限受到限制时(即您无法创建新表或访问系统资源),这可能会起作用:

SELECT "Mike" AS FName
FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual
Run Code Online (Sandbox Code Playgroud)
  1. anyTable是您找到的第一个用户表(我很难想象现实生活中的数据库没有用户表!)。

  2. WHERE 1=0应该快速返回 0 计数,即使在一个大表上也是如此(希望 Jet 引擎足够聪明,能够识别这种微不足道的条件)。