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

这按预期工作:

SELECT "Mike" AS FName 

这会失败,并显示错误“查询input必须包含至less一个表或查询”:

 SELECT "Mike" AS FName UNION ALL SELECT "John" AS FName 

这只是Jet / ACE数据库引擎的一个怪癖/限制,还是我错过了一些东西?

你没有忽略任何东西。 Access的数据库引擎将允许一个没有FROM数据源的单行SELECT 。 但是,如果你想UNIONUNION ALL多行,你必须包含一个FROM …即使你没有引用来自该数据源的任何字段。

我用一行创build了一个表,并添加了一个检查约束来保证它总是只有一行。

 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 

Dual表对于这样的查询是有用的:

 SELECT "foo" AS my_text FROM Dual UNION ALL SELECT "bar" FROM Dual; 

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

注意检查约束是使用Jet 4添加的,并且仅适用于从ADO执行的语句。 CurrentProject.Connection.Execute strSql工作,因为CurrentProject.Connection是一个ADO对象。 如果您尝试使用DAO(即CurrentDb.Execute或Access查询devise器)执行相同的语句,则会出现语法错误,因为DAO无法创build检查约束。

如果你有权访问一些系统表,你可以这样模拟一个双重表:

 (SELECT COUNT(*) FROM MSysResources) AS DUAL 

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

  • 始终可用,可读(MSysObjects可能无法访问每个连接)
  • 只包含一条logging,如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 

例如,这就是在jOOQ中作为句法元素实现的东西。

当你限制对数据库的只读访问(即你不能创build新表或访问系统资源)时,这可能会起作用:

 SELECT "Mike" AS FName FROM (SELECT COUNT(*) FROM anyTable WHERE 1=0) AS dual 
  1. anyTable是你find的第一个用户表(我几乎无法想象一个没有用户表的真实数据库!)。

  2. 在1 = 0的情况下,即使在一张大桌子上,也应该快速返回一个0的计数(希望Jet引擎足够聪明,可以识别这种微不足道的情况)。

如果有人想要使用Top 1方法,它看起来像这样:

 SELECT first_name AS FName FROM tblname UNION ALL SELECT "Mike" as Fname FROM (Select Top 1 Count(*) FROM tblsometable); 

该字段的别名必须在联合的两侧相同,在本例中为“FName”。

这是一个更简单的方法来做到这一点:

 SELECT 'foo', 'boo', 'hoo' from TableWith1Row union SELECT 'foo1', 'boo1', 'hoo1' from TableWith1Row 

重要的是:TableWith1Row可以是只有1个logging(无论如何你都忽略)的表,或者它可以是任意行数的表(必须至less有1行),但是你需要添加一个WHERE子句来保证1行。 这有点松散,但是这是一个快速的方法,不需要创build更多的表。

Interesting Posts