【问题标题】:Converting SQL Query to Access Query - SELECT within SELECT将 SQL 查询转换为访问查询 - SELECT 中的 SELECT
【发布时间】:2025-12-16 09:05:02
【问题描述】:

我在 SQL Server 中有一个查询,我试图将它转换为 MS-Access 2003 中的一个查询。该查询旨在用作报告的基础。该报告有两个字段..“已分配案例”和“已关闭案例”。

SELECT 
(SELECT COUNT(*) 
FROM CaseDetail 
WHERE CaseAssignedDate Between '1/1/2008' AND '1/1/2009') as 'Cases Assigned',
(SELECT COUNT(*) 
FROM CaseDetail 
WHERE CaseClosedDate BETWEEN '1/1/2008' AND '1/1/2009') as 'Cases Closed'

我在 Access 2003 中使用 SQL 时遇到困难。为了 Access 的缘故,我已将 ' 字符替换为 #,但仍然没有乐趣。 Access 在 SELECT 语句中是否存在 SELECT 问题?我从 Access 得到的错误没有什么帮助。

Reserved error (-3205); there is no message for this error

另外,如果 SQL 语句需要从多个表中获取数据怎么办。比如……

SELECT 
(SELECT COUNT(*) 
FROM AssignedCases
WHERE CaseAssignedDate Between '1/1/2008' AND '1/1/2009') as 'Cases Assigned',
(SELECT COUNT(*) 
FROM ClosedCases
WHERE CaseClosedDate BETWEEN '1/1/2008' AND '1/1/2009') as 'Cases Closed'

这在 SQL 中有效,但在 Access 中无效。

【问题讨论】:

    标签: sql sql-server ms-access


    【解决方案1】:

    我不知道您从哪里收到此错误消息,但您的问题是尝试在没有表或查询的情况下执行 Select 语句。您需要某种只有一条记录的“虚拟”表来完成此操作。

    SELECT  
        (SELECT COUNT(*)  
         FROM CaseDetail  
         WHERE CaseAssignedDate Between '1/1/2008' AND '1/1/2009'
        ) as 'Cases Assigned', 
        (SELECT COUNT(*)  
         FROM CaseDetail  
         WHERE CaseClosedDate BETWEEN '1/1/2008' AND '1/1/2009'
        ) as 'Cases Closed' 
    FROM DummyTableWithOneRecord;
    

    【讨论】:

    • 你能解释一下为什么需要这个“DummyTableWithOneRecord”吗?似乎有点骇人听闻。记录是否必须包含一定数量的字段?具体名称?
    • 我应该解释一下我所说的 hack 是什么意思。不是以一种糟糕的方式破解,但更多的是我真的不明白它是如何工作的。我尝试了你的建议,但我得到了一个 NULL 结果集。没有行也没有字段。
    • + 用于实际回答问题,即 Select 语句需要一个表格。
    • @webworm:“为什么需要这个“DummyTableWithOneRecord”?看起来有点小技巧。” -- 在标准 SQL 中,SELECT 需要一个表。对于更改,Access 做对了 :) SQL Server 通过允许您在没有表的情况下使用SELECT 来提供“hack”,例如SELECT 1; 在 SQL Server 上有效,并且实际上也返回了一个结果集,但违反了标准 ...或扩展它,如果您愿意的话:) 要正确地(或在 Access 上)执行此操作,您需要 SELECT 1 FROM AnyTable; 假设 AnyTable 完全一行或SELECT DISTINCT 1 FROM AnyTable; 假设 AnyTable 至少有一行。
    • @Jeff O: "Select 1 as TheOne; will work in [ACE] 2007" -- 确实相当于我的SELECT 1 FROM AnyTable;,假设TheOne 只有一行。
    【解决方案2】:

    我目前还没有要测试的 Windows 机器,但这样的东西应该可以工作。

    SELECT SUM(IIF(CaseAssignedDate 
               BETWEEN #1/1/2008# AND #1/1/2009#, 1, 0)) AS CasesAssigned,
           SUM(IIF(CaseClosedDate 
               BETWEEN #1/1/2008# AND #1/1/2009#, 1, 0)) AS CasesClosed
      FROM CaseDetail 
    

    根据我的经验,通常最好尽可能避免在 Access 中使用子查询。


    编辑:
    回应您的评论,我刚刚测试了 Access 是否允许这种替代方法:

    SELECT *
      FROM
    (
    SELECT 'CasesAssigned', COUNT(*) AS Total
      FROM AssignedCases
     WHERE CaseAssignedDate BETWEEN #1/1/2008# AND #1/1/2009#
    
    UNION ALL
    
    SELECT 'ClosedCases', COUNT(*) AS Total
      FROM ClosedCases
     WHERE CaseClosedDate BETWEEN #1/1/2008# AND #1/1/2009#
    );
    

    Edit2:
    littlegreen's answer 可以在您需要单行结果集时使用。

    【讨论】:

    • 如果所有数据都来自一个表,则此方法有效。如果需要查询其他表怎么修改?
    • @webworm:请看我的编辑。我不太确定拆分这些数据是最好的表结构。然而,这完全是另一个问题。祝你好运。
    • @webworm:那么,littlegreen 的答案很理想。
    【解决方案3】:

    由于您有一个可在 SQL Server 中运行的查询,因此请创建一个 Access 传递查询,该查询使用该查询(在 SQL Server 中)并将结果集返回给 Access。

    或者,基于该 SELECT 语句创建一个 SQL Server 视图并从 Access 链接到该视图。

    由于它已经在 SQL Server 中运行,我看不到在 Access 中重新创建查询有任何附加价值。

    【讨论】:

    • 嗯,在 Access 中它肯定不能是 OUTER JOIN!
    【解决方案4】:

    Access 和 SQL Server 都允许嵌套查询,但至少在 SQL Server 中,它要求您为嵌套查询设置一个虚拟别名,并且嵌套查询中的所有列都需要一个名称。这可能导致了错误。

    我建议以下查询:

    SELECT q1.CasesAssigned, q2.CasesClosed
    FROM 
    (SELECT COUNT(*) AS CasesAssigned
    FROM CaseDetail 
    WHERE CaseAssignedDate Between '1/1/2008' AND '1/1/2009') as q1,
    (SELECT COUNT(*) AS CasesClosed
    FROM CaseDetail 
    WHERE CaseClosedDate BETWEEN '1/1/2008' AND '1/1/2009') as q2
    

    【讨论】:

    • 我在 Access 中运行了它,它成功了!这对我来说是理想的,因为我需要聚合来自单独和不相关表中的字段的数据。这允许将所有聚合数据收集为单行结果集,允许我将其用作报告的基础。谢谢@littlegreen!
    • “SQL 服务器要求您为嵌套查询设置一个虚拟别名,并且嵌套查询中的所有列都需要一个名称”——我认为您误读了该查询:这些是SELECT 子句并且不需要列“别名”或表相关名称。您似乎在谈论 FROM 子句中的派生表。
    • 在这种情况下,'as q1' 和 'as q2' 可以省略。我目前无法对其进行测试,但您可能是对的。
    【解决方案5】:

    3205 错误是交叉表列标题太多。

    这个查询解决方案适合你吗:

    SELECT 'Cases Asssigned' as Type, COUNT(*) 
    FROM CaseDetail 
    WHERE CaseAssignedDate Between '1/1/2008' AND '1/1/2009'
    UNION
    SELECT 'Cases Closed'as Type, COUNT(*) 
    FROM CaseDetail 
    WHERE CaseClosedDate BETWEEN '1/1/2008' AND '1/1/2009')
    

    结果将在两行而不是一行。

    【讨论】:

    • 既然这将是报告的基础,有没有办法将结果作为 1 行多列返回?