Excel VBA SQL Join Syntax ErrorExcel VBA SQL 连接语法错误

2023-10-13 16:47:51 浏览数 (1)

【问题标题】:Excel VBA SQL Join Syntax ErrorExcel VBA SQL 连接语法错误 【发布时间】:2015-09-24 00:08:56 【问题描述】:

我正在编写一个允许用户从列表框中选择客户的子程序。选择记录为 CustomerID(整数变量)并用于查询 Access 数据库文件。然后,子应将有关指定客户的销售信息输出到 Excel 工作表,特别是:

  1. 订购日期
  2. 订单编号
  3. 总订单成本(定义为售出数量 * 售出价格)

访问文件有 3 个我需要的表:Customers、Orders、LineItems

我下面的代码应该将客户 ID 连接到订单 ID 字段,然后将其与订单 ID 连接起来,并将订单 ID 连接到订单项上。

代码语言:javascript复制
' Define SQL statement to get order info for selected product.
SQL = "SELECT O.OrderDate, COUNT(O.OrderID), SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost] " _
        & "FROM (((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _
        & "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems L " _
        & "ON O.OrderID = L.OrderID)" _
        & "WHERE O.CustomerID =" & CustomerID & " " _
        & "GROUP BY O.OrderDate, O.OrderID" _
        & "ORDER BY O.OrderDate"

我不断收到“FROM 子句中的语法错误”。我的 JOIN 语句是否正确?我玩过(),“”等但没有成功。我已经检查并且表名称是正确的(订单、客户、LineItems)字段名称也拼写正确。

【问题讨论】:

  • ON 子句和 WHERE 之间或 group by 和 order by 之间没有空格。
  • 您不想将 orderid 加入 customerid ......这些是不匹配的不同 ID。只需删除该部分。此外,语法无论如何都不起作用。你不能做 INNER JOIN ON....你需要在 INNER JOIN 和 ON 之间放一个表。如果您想使用两个字段进行连接,则语法为“...C INNER JOIN Orders O ON C.CustomerID = O.Customer ID AND C.CustomerID = O.OrderID” 同样,我怀疑这实际上是您想要。
  • 感谢 OpiesDad,所以我应该创建一张桌子来容纳我需要的东西吗?我看不出答案那么复杂。你也是对的,我不认为我想加入使用两个字段。你能建议一些方向吗?我不明白为什么我不能将 OrderID 与 CustomerID 关联起来?它们确实有不同的值,但在“订单”表中,订单 ID 是主键,客户 ID 是外键。这似乎是最好的路线,因为表“ListItems”没有 CustomerID 作为外键。 (ListItems 有输出所需的订单详情)
  • 见下面的答案。 OrderID 已经与 CustomerID 相关,因为它们都在 Order Table 中。所以每条记录都有一个与它们相关的记录。 ListItems 将 OrderID 作为外键,因此通过 Order 表链接到 customerID。
  • 尝试将debug.print sql 直接放在它下面并检查VBE 的即时窗口(Ctrl G)以查看您制作的内容。将其粘贴到空白的 Access 查询中并进行修改,直到它起作用,然后将更改传输回字符串构造并重新测试.

【解决方案1】:

我喜欢使用带有空格分隔符的数组和 Join 方法。这样可以确保我不会遗漏任何空格(@McAdam133 指出您这样做了)。

代码语言:javascript复制
Dim aSql(1 To 6) As String

aSql(1) = "SELECT O.OrderDate, COUNT(O.OrderID), SUM([L.QuantityOrdered]*[L.QuotedPrice]) AS TotalCost"
aSql(2) = "FROM (Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)"
aSql(3) = "INNER JOIN LineItems L ON O.OrderID = L.OrderID"
aSql(4) = "WHERE C.CustomerID = " & CustomerID
aSql(5) = "GROUP BY O.OrderDate"
aSql(6) = "ORDER BY O.OrderDate"

Set rs = CurrentProject.Connection.Execute(Join(aSql, Space(1)))

以下是我对不起作用的内部联接的建议。在 Access 中创建一个查询并查看它生成的 SQL。它可能不是最漂亮的 SQL,但它可以帮助您确定问题所在。如果您将客户、订单和 LineItems 放在查询窗口中,必要时绘制箭头(默认情况下可能会出现),并在其中放置几个​​字段,Access 将生成类似

代码语言:javascript复制
SELECT Orders.OrderID, Orders.OrderDate, LineItems.QuantityOrdered, LineItems.QuotedPrice
FROM (Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID) INNER JOIN LineItems ON Orders.OrderID = LineItems.OrderID;

这不会对任何内容进行分组或使用别名,但它会为您提供工作声明。然后您可以使用别名和分组进行修改,并在此过程中对其进行测试。

从你的例子:

代码语言:javascript复制
& "FROM (((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _

这条线不错。您正在使用来自 Customers 的主键和可能在 Orders 中的外键加入订单中的客户。

代码语言:javascript复制
& "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems as L " _

我不确定第一次加入想要完成什么,但正如@OpiesDad 评论的那样,这不是你想要的。您已经在第一行成功地加入了 Customers 和 Orders,因此您可以获取该加入的结果并将其加入 LineItems(上面的 aSql(3))。第二个连接(到 LineItems)看起来不错。

您可以在多个字段上连接两个表。就像你有两张客户表,你想看看是否有任何重叠。

代码语言:javascript复制
FROM Wholesale INNER JOIN Retail ON Wholesale.CustomerName = Retail.CustName AND Wholesale.State = Retail.StateOrProvince

根据您显示的结构,您的所有表中都有很好的唯一主键,因此不需要连接多个字段。

最后,您将根据 OrderID 进行分组。它不会导致错误,但它也没有做任何事情。您在 SELECT 部分的聚合函数中使用 OrderID。您应该聚合您想要聚合的字段,并按您不聚合的字段进行分组。

【讨论】:

【解决方案2】:

INNER JOIN 中的表创建别名时,必须使用AS

代码语言:javascript复制
' Define SQL statement to get order info for selected product.
SQL = "SELECT O.OrderDate, COUNT(O.OrderID), SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost] " _
        & "FROM (((Customers as C INNER JOIN Orders O ON C.CustomerID = O.CustomerID) " _
        & "INNER JOIN ON O.OrderID = O.CustomerID) INNER JOIN LineItems as L " _
        & "ON O.OrderID = L.OrderID)" _
        & "WHERE O.CustomerID =" & CustomerID & " " _
        & "GROUP BY O.OrderDate, O.OrderID" _
        & "ORDER BY O.OrderDate;"

可以肯定的是,用; 终止语句。

【讨论】:

  • 您不需要在 Access 中执行此操作,并且此代码仍然无法工作,因为它没有解决我没有时间制定的许多其他问题完整的答案。

【解决方案3】:

您遇到的问题是您尝试执行的连接没有意义。

让我们先获取相关订单,然后添加订单项,这样可以让解释更简单。

为此,您需要 SQL:

代码语言:javascript复制
SELECT C.CustomerID, C.CustomerName, O.OrderID, O.OrderDate
FROM Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID
WHERE C.CustomerID = 15
ORDER By O.OrderDate

请注意,这假定您要查找的客户的 ID 为 15。

这将为您提供所请求客户的所有订单的升序列表。

如果你想要订单项,那么你也需要链接到这个表格:

代码语言:javascript复制
 SELECT C.CustomerID, C.CustomerName, O.OrderId, O.OrderDate
     , SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost]
 FROM ((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)
              INNER JOIN LineItems L ON O.OrderID = L.OrderID)
 WHERE C.CustomerID = 15
 GROUP BY C.CustomerID, C.CustomerName, O.OrderID, O.OrderDate
 ORDER BY O.OrderDate

这很可能是您要查找的查询。您列出的第二个 INNER JOIN 是多余的,没有意义。您不想将 OrderID 与 CustomerID 匹配,您需要与该客户匹配的订单列表。 C 到 O 上的第一个 INNER JOIN 已经创建了这个。 where 子句将客户表限制为只有一个客户。

要将其放入您的代码中,只需将表单中的“15”替换为“CustomerID”即可。

此外,根据 McAdam 的评论,您在几个地方缺少空格。为了解决这个问题,我建议将所有空格作为行首,这样你就可以确保它们在那里(如下所示)。最终代码应如下所示(从输出中删除客户信息):

代码语言:javascript复制
 SQL = "SELECT O.OrderDate, O.OrderID" _
    & ", SUM(L.QuantityOrdered * L.QuotedPrice) AS [TotalCost]" _
    & " FROM ((Customers C INNER JOIN Orders O ON C.CustomerID = O.CustomerID)" _
    & " INNER JOIN LineItems L ON O.OrderID = L.OrderID)" _
    & " WHERE O.CustomerID =" & CustomerID _
    & " GROUP BY O.OrderDate, O.OrderID" _
    & " ORDER BY O.OrderDate"
复制

您似乎也并不真正想要 orderID 的计数,所以我把它去掉了,因为它也没有太大意义。

【讨论】:

  • 感谢您的回复 OpiesDad,您在第一条评论中暗示了答案,我推迟检查线程,直到完成(可以显示保存时间)。她的工作就像一颗宝石,丹克申
  • 如果它解决了问题并且您认为它是最好的,请将此标记为答案。很高兴能帮上忙。

0 人点赞