来自Sybase的隐秘SQL错误(错误-680)

时间:2012-12-01 16:40:06

标签: sql sqlanywhere dynamic-queries

我尝试在针对Sybase SQL-Anywhere数据库的PHP中运行动态生成的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中),返回正确的结果集:

查询A:

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

澄清我想要的回报结果:

enter image description here

关于error -680

Sybase documentation说明如下:

  

使用Transact-SQL的查询的WHERE子句中的表达式   语法包含来自NULL提供表的列的比较   使用子查询或引用另一列的列表达式   表

  1. 原始SQL查询无效?

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

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

  4. 请注意,由于此查询是动态生成的,我想知道如何更改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
      )
    

2 个答案:

答案 0 :(得分: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,因此我只使用了ONCE库存主数据。然后,对该外键匹配的股票库存链接折扣(SILD别名)进行LEFT-JOIN和相应的“DIS_FK”ID(分别为6,14,25)。

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

这将我们带到WHERE子句。对于这个库存项目,我想确保至少一个条目为空(即:对于折扣14),并且至少存在一个DID项目(即: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有效,0失败,3失败......

如果你有6个标准,那么1到5 ......

答案 1 :(得分: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的未加引号的引用混淆了。另一种可能性是范围表已满(如果你有很多子查询术语)