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
。 但是,如果你想UNION
或UNION 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 1
或WHERE
子句的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
-
anyTable是你find的第一个用户表(我几乎无法想象一个没有用户表的真实数据库!)。
-
在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更多的表。