将 WHERE 语句添加到引用 ODBC link 的子查询时,访问查询失败

Access query fails when WHERE statement is added to subquery referencing ODBC link

原始post

给定两个 table 结构如下:

t1 (finished goods)      t2 (component parts)

sku  | desc  | fcst       sku  | part   | quant
0001 | Car   | 10000      0001 | wheel  | 4
0002 | Boat  | 5000       0001 | door   | 2
0003 | Bike  | 7500       0002 | hull   | 1
0004 | Shirt | 2500       0002 | rudder | 1
...  | ...   | ...        0003 | wheel  | 2
                          0005 | rotor  | 2
                          ...  | ...    | ...

我正在尝试将车轮要求附加到预测中,同时将所有记录保留在预测中。我的结果如下所示:

sku  | desc  | fcst  | wheels | wheelfcst
0001 | Car   | 10000 | 4      | 40000
0002 | Boat  | 5000  |        |
0003 | Bike  | 7500  | 2      | 15000
0004 | Shirt | 2500  |        |
...  | ...   | ...   | ...    | ...

在我看来,解决此问题的最有效方法类似于以下查询:

SELECT 
    t1.sku, 
    t1.desc, 
    t1.fcst, 
    q.quant as wheels, 
    t1.fcst * q.quant as wheelfcst
FROM
    t1 
    LEFT JOIN
        (
            SELECT *
            FROM t2
            WHERE part LIKE "wheel"
        )
        as q
    ON t1.sku = q.sku

问题是当 运行 时它给出了一个非常复杂的 Invalid Operation. 错误。

如果我删除 WHERE 语句:我得到了所需的轮子部件,但我也拉了门、船体和方向舵数量。

如果我将 WHERE 语句移动到主查询 (WHERE q.part LIKE "wheel"):我只看到包含轮子的货物,但结果中缺少船。

我考虑过一个UNION语句,把前面提到的将WHERE移出子查询(WHERE q.part LIKE "wheel")的结果,但似乎没有抓取每个没有轮子组件的最终项目的好方法,因为每个 sku 可以有 0 到多个组件。

在我想要的查询中是否有我忽略的东西,或者这是否需要 UNION 方法?

编辑 #1 - 回答 Andre

提出的问题

另外我是Access 2007,可能是软件版本问题

将子查询变为临时 table 可行,但目标是避免该过程。

编辑 #2 - 我环境中的缺陷

我创建了一个与我在此处 post 编辑的相同的测试场景,我得到了与 Andre 相同的结果。在这一点上,将这些结果与临时 table 方法确实有效的事实相结合,我相信这是查询复杂性和记录访问的问题。尽管错误消息不是典型的 Query is too complex. 消息。

编辑 #3 - 深入挖掘 "Complexity"

我的下一个测试是使 where 子句更简单。可悲的是,我工作的系统每天午餐时更新,目前我无法访问任何数据服务器。我希望在今天晚些时候更新我的进度。

编辑 #4 - 替换部分搜索

好的,我们开完会回来准备出发了。我只有 运行 六个查询,其中包含三个不同的 WHERE 子句:

WHERE part LIKE "*heel" / WHERE component_item LIKE "*SBP"(原大号)
适用于小规模测试,Invalid operation 适用于大规模测试。

WHERE part LIKE "wheel" / WHERE component_item LIKE "VALIDPART" (原小尺度)
适用于小规模测试,Invalid operation 适用于大规模测试。

WHERE part LIKE "wh33l" / WHERE component_item LIKE "NOTVALIDPART"(Where语句没有return任何记录)

Small Scale 
sku  | desc  | fcst  | wheels | wheelfcst
0001 | Car   | 10000 |        |
0002 | Boat  | 5000  |        |
0003 | Bike  | 10000 |        |
0004 | Shirt | 5000  |        |

Large Scale
sku  |description |forecast |component_item |dip_rate
#####|RealItem1   | ######  |               |
#####|RealItem2   | ######  |               |
#####|RealItem3   | ######  |               |
...  |...         | ...     |               |

Tl;dr 过滤器细节没有影响,除非过滤器产生一个 returned 0 条记录的子查询。

编辑 #5 - 一个有趣的结果

在尝试所有可能的解决方案并尽我所能进行测试的想法下,我创建了一个本地临时文件 table,其中包含 t2 (~25MB) 中的每个字段和每条记录。引用此 table 而不是 ODBC link 到 t2 适用于部分搜索查询 (WHERE component_item LIKE "*SBP")。我正在更新此问题的标题以反映该问题特定于 linked table.

我将示例数据复制到 Access 2010 和 运行 查询,它没有问题。

您收到的完整错误消息是什么? ("very elaborate Invalid Operation.")

你的表中有多少条记录?

skut1中的主键吗?

无论如何,我建议将子查询更改为:

SELECT sku, quant
FROM t2
WHERE part = "wheel"

LIKE 仅用于部分搜索。

解决方法

我设计了一组查询,这些查询使用我对 UNION 语句的一个原始预感。希望这能让任何偶然发现这个问题的人节省一点时间。

正在设置 UNION

我最初的问题是没有办法只 select 轮记录然后将它们加入空记录,因为(以 t1 为例)船有零件t2,但其中 none 是轮子。我必须首先设计一种方法来查看哪些产品有轮子而不使用过滤器。

我的中间方案:

Query: t1haswheel
SELECT
    t1.sku, 
    t1.desc, 
    t1.fcst, 
    SUM(
        IF(
            t2.part = "wheel",
            1, 0
          ) as haswheel
FROM
    t1 
    LEFT JOIN
        (
            SELECT *
            FROM t2
            WHERE part LIKE "wheel"
        )
        as q
    ON t1.sku = q.sku
GROUP BY
    t1.sku, 
    t1.desc, 
    t1.fcst

此查询 returns 来自 t1 的每条记录,后跟一个基于该项目编号的部件列表中 wheel 记录数的数字。如果 t2 中没有记录,字段 part 中有 "wheel",则查询 returns 0 记录。此列表是我在原始问题中的 UNION 语句所需要的。

UNION-把它们放在一起

此时,所需要的只是一个 UNION,它使用来自先前查询 (haswheel) 的求和字段。

SELECT
    q1.sku, 
    q1.desc,
    q1.fcst,
    t2.quant,
    q1.fcst * t2.quant as wheelfcst
FROM 
    t1haswheel as q1
    LEFT JOIN t2
    ON q1.sku = t2.sku
WHERE 
    q1.haswheel > 0 AND
    t2.part = "wheel"

UNION ALL

SELECT
    q1.sku, 
    q1.desc,
    q1.fcst,
    null,
    null
FROM 
    t1haswheel as q1

WHERE q1.haswheel = 0

这从带轮子的记录中提取正确的结果,然后附加不带轮子的记录,同时从不在引用 ODBC 链接的子查询中使用 WHERE 语句 table:

sku  | desc  | fcst  | wheels | wheelfcst
0001 | Car   | 10000 | 4      | 40000
0003 | Bike  | 7500  | 2      | 15000
...  | ...   | ...   | ...    | ...
0002 | Boat  | 5000  |        |
0004 | Shirt | 2500  |        |
...  | ...   | ...   | ...    | ...