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

时间:2011-10-28 18:50:15

标签: sql ms-access jet

这可以按预期工作:

SELECT "Mike" AS FName

此操作失败并显示错误“查询输入必须至少包含一个表或查询”:

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

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

7 个答案:

答案 0 :(得分:21)

你没有忽视任何事情。访问'数据库引擎将允许单行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

Dual表对此类查询非常有用:

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

我看到的另一种方法是使用SELECT语句和TOP 1WHERE子句将结果集限制为单行。

注意检查约束是使用Jet 4添加的,仅适用于从ADO执行的语句。 CurrentProject.Connection.Execute strSql有效,因为CurrentProject.Connection是ADO对象。如果您尝试使用DAO(即CurrentDb.Execute或来自Access查询设计器)执行相同的语句,则会出现语法错误,因为DAO无法创建检查约束。

答案 1 :(得分:5)

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

(SELECT COUNT(*) FROM MSysResources) AS DUAL

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

  • 始终可用,可读(每个连接可能无法访问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

这就是jOOQ中作为句法元素实现的内容,例如。

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

这是一种更简单的方法:

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

重要说明:TableWith1Row可以是一个具有字面上1条记录的表(无论如何你都会忽略它)或者它可以是一个包含任意行数的表(必须至少有1行)但是你要添加一个WHERE子句以确保1行。这有点松散,但它是一种快速的方法,可以在不创建更多表格的情况下完成这项工作。

答案 4 :(得分:0)

如果有人想使用Top 1方法,它将如下所示:

%X1234123412341234^B>NURBz>C>P>XY JDAE^1903000000000000000Zs1234123412341234]1903000000000000000Z

字段的别名必须在联合的两边相同,在这种情况下" FName"。

答案 5 :(得分:0)

输入任何表名(您实际上不需要从中选择一列)。

此查询为我提供了下拉菜单所需的3个会计年度。会计年度从七月开始。

SELECT IIf(Month(Now())>6,Year(Now())-1,Year(Now())-2) AS FY
FROM table
UNION 
SELECT IIf(Month(Now())>6,Year(Now()),Year(Now())-1) AS FY
FROM table
UNION 
SELECT IIf(Month(Now())>6,Year(Now())+1,Year(Now())) AS FY
FROM table;

答案 6 :(得分:-1)

这是在访问中实际起作用的查询。我测试了它使用子查询作为“双重” :(从MSysObjects中选择SELECT count(*)作为cnt)。

select 1 as a from (SELECT count(*) as cnt from MSysObjects) UNION ALL
select 2 as a from (SELECT count(*) as cnt from MSysObjects) UNION ALL
select 3 as a from (SELECT count(*) as cnt from MSysObjects)