2

我尝试在 PHP 中针对 Sybase SQL-Anywhere 数据库运行动态生成的 SQL 查询,但出现以下错误:

Warning: sybase_query(): message: SQL Anywhere Error -680: Invalid expression in WHERE clause of Transact-SQL outer join (severity 16) in /path/to/file.php

SQL 查询字符串:

SELECT DISTINCT v_InventoryMaster.INV_ScanCode, v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster
WHERE ( v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 6 
  )
  OR v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 14 
  )
  OR v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 25 
  )
  -- more OR clause subqueries with different ILD_DIS_FK values
)
ORDER BY v_InventoryMaster.INV_ScanCode

我对 SQL 或与数据库的接口并不完全陌生,但这条消息让我很困惑。它声称WHERE子句中有一个无效的表达式,但我看不到查询的结构是如何非法的。我的猜测是错误涉及OR两个搜索结果的合并。

此外,通过运行这三个单独的查询并组合结果(在 Excel 中),返回正确的结果集:

查询一:

SELECT DISTINCT v_InventoryMaster.INV_ScanCode, v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster
WHERE ( v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 6 
  )
ORDER BY v_InventoryMaster.INV_ScanCode

查询 B

SELECT DISTINCT v_InventoryMaster.INV_ScanCode, v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster
WHERE ( v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 14 
  )
ORDER BY v_InventoryMaster.INV_ScanCode

查询 C

SELECT DISTINCT v_InventoryMaster.INV_ScanCode, v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster
WHERE ( v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = 25 
  )
ORDER BY v_InventoryMaster.INV_ScanCode

为了澄清我想要的返回结果:

在此处输入图像描述

关于Sybase 文档error -680的内容如下:

使用 Transact-SQL 语法的查询的 WHERE 子句中的表达式包含将提供 NULL 的表中的列与子查询或引用另一个表中的列的表达式进行比较。

  1. 原始 SQL 查询有什么无效之处?

  2. 记录在案的解释是什么意思?

  3. 如何编辑原始 SQL 查询以获得所需的结果?

请注意,由于此查询是动态生成的,我想知道如何更改子句之间的OR语句:

语句结构:

  v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = value -- value dynamically chosen by user
  )
4

2 回答 2

2

“NOT IN”查询非常昂贵,特别是如果您像示例中那样应用它 3 次以上。我会旋转这个与使用“NOT IN”查询略有不同。我会离开加入并寻找任何为 NULL 的条目(即:未找到),但至少有一个具有条件的条目......

SELECT DISTINCT 
      vIM.INV_ScanCode, 
      vIM.INV_ReceiptAlias 
   FROM
      ecrs.v_InventoryMaster vIM
         LEFT JOIN ecrs.StockInventoryLinkDiscounts SILD6
            ON vIM.INV_PK = SILD6.ILD_INV_FK
            AND SILD6.ILD_DIS_FK = 6 
         LEFT JOIN ecrs.StockInventoryLinkDiscounts SILD14
            ON vIM.INV_PK = SILD14.ILD_INV_FK
            AND SILD14.ILD_DIS_FK = 14 
         LEFT JOIN ecrs.StockInventoryLinkDiscounts SILD25
            ON vIM.INV_PK = SILD25.ILD_INV_FK
            AND SILD25.ILD_DIS_FK = 25 
   WHERE
          (    SILD6.ILD_INV_FK IS NULL
            OR SILD14.ILD_INV_FK IS NULL
            OR SILD25.ILD_INV_FK IS NULL )
      AND (  case when SILD6.ILD_INV_FK IS NULL THEN 0 ELSE 1 end
           + case when SILD14.ILD_INV_FK IS NULL THEN 0 ELSE 1 end
           + case when SILD25.ILD_INV_FK IS NULL THEN 0 ELSE 1 end ) > 0
   ORDER BY 
      vIM.INV_ScanCode

由于您的每个标准都是基于 PK 条目的 NOT IN,因此我只使用了一次库存主控。然后,对该外键匹配和相应的“DIS_FK”ID(分别为 6、14、25)进行 LEFT-JOIN 到库存链接折扣(SILD 别名)。

所以,现在,假设特定库存项目在 (SILD) 级别有 10 个折扣,包括 ID 1、6、10、11、22、25、等等、等等……此表将加入以查找匹配项同时为 6 和 25(通过不同的别名)找到 14 的一个。从你的场景中,你会想要这个条目。

这将我们带到 WHERE 子句。对于这一个库存项目,我想确保至少有一个条目为 NULL(即:折扣 14),并且至少有一个项目存在(即:6 和 25)。

现在,如果库存主数据有 1、5、12 的折扣,它将被忽略,因为不会发现 6、14 或 25 中的 NONE 从未考虑 WHERE 子句的其余部分。

您可以根据需要继续添加尽可能多的 (SILD) 实例,并保持模式继续运行,只需使用(正如我所拥有的)不同的别名来知道您指的是哪个。

WHERE 子句甚至可以更简化为以下内容

   WHERE
      (  case when SILD6.ILD_INV_FK IS NULL THEN 0 ELSE 1 end
           + case when SILD14.ILD_INV_FK IS NULL THEN 0 ELSE 1 end
           + case when SILD25.ILD_INV_FK IS NULL THEN 0 ELSE 1 end ) between 1 and 2

因此,这样,您至少有一个条件符合条件,但最多比您的所有条件少 1 个。在此示例中,您有 3 个条件,因此 1 OR 2 将是有效的,零失败,三个失败......

如果您有 6 个标准,那么在 1 到 5 之间...

于 2013-01-13T17:22:17.967 回答
1

您可以简单地替换片段:

v_InventoryMaster.INV_PK NOT IN (
    SELECT DISTINCT v_InventoryMaster.INV_PK 
    FROM ecrs.v_InventoryMaster, ecrs.StockInventoryLinkDiscounts
    WHERE v_InventoryMaster.INV_PK = StockInventoryLinkDiscounts.ILD_INV_FK
    AND StockInventoryLinkDiscounts.ILD_DIS_FK = value -- value dynamically chosen by user
  )

经过:

 NOT EXISTS (
    SELECT * 
    FROM  ecrs.StockInventoryLinkDiscounts sild
    WHERE sild.ILD_INV_FK = tbl.INV_PK
    AND sild.ILD_DIS_FK = value -- value dynamically chosen by user
    --           ^^^^^ NOTE: this should probably be sild.ILD_DIS_PK
  )

是外部查询tbl的相关名称;外部查询将变为:

SELECT DISTINCT v_InventoryMaster.INV_ScanCode
      , v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster tbl

另请注意,我ecrs.v_InventoryMaster从子查询中删除了该表,因为它已经存在于外部查询中,并且会导致检查与外部查询已经找到的完全相同的行。

这将给出完整的查询:

SELECT DISTINCT v_InventoryMaster.INV_ScanCode
      , v_InventoryMaster.INV_ReceiptAlias 
FROM ecrs.v_InventoryMaster tbl
WHERE NOT EXISTS (
    SELECT * 
    FROM  ecrs.StockInventoryLinkDiscounts sild
    WHERE sild.ILD_INV_FK = tbl.INV_PK
    AND sild.ILD_DIS_FK = 6
  )
OR NOT EXISTS (
    SELECT * 
    FROM  ecrs.StockInventoryLinkDiscounts sild
    WHERE sild.ILD_INV_FK = tbl.INV_PK
    AND sild.ILD_DIS_FK = 14
  )
OR NOT EXISTS (
    SELECT * 
    FROM  ecrs.StockInventoryLinkDiscounts sild
    WHERE sild.ILD_INV_FK = tbl.INV_PK
    AND sild.ILD_DIS_FK = 25
  )
;

我的猜测是解析器被对ecrs.v_InventoryMaster. 另一种可能性是范围表已满(如果您有很多子查询项)

于 2013-01-13T17:06:53.187 回答