0

我从几个表中选择数据,但主要思想是产品可能有也可能没有与之相关的折扣记录,如折扣百分比或折扣金额。我正在使用左外连接(这可能不正确),并且无论记录是否存在,我都会返回相同的美元值和百分比值。

查询类似于:

SELECT Items.ItemID, Items.name, Items.price, 
       ItemDiscounts.percentOff, ItemDiscounts.dollarOff, 
       ItemAttributes.ColorName, ItemStuff.StuffID
FROM Items, ItemAttributes, ItemStuff
LEFT OUTER JOIN ItemDiscounts
  ON ItemDiscounts.ItemID = ItemID
  AND (
    ItemDiscounts.percentOff > 0
    OR ItemDiscounts.dollarOff > 0
  )
WHERE Items.ItemID = ItemAttributes.ItemID
AND ItemStuff.ItemID = Items.ItemID
GROUP BY ItemStuff.StuffID

奇怪的是,在所有结果中,percentOff返回“1”,并dollarOff返回“0”,不管每个项目是否有它自己的关联折扣记录。对于吐口水,我改为ItemDiscounts.percentOff > 0ItemDiscounts.percentOff > 1然后dollarAmount改为全 2 和percentOff全 0。

我对此感到有些困惑,因此将不胜感激。

4

3 回答 3

1

您在 ON 子句中有对 ItemID 的不合格引用……不清楚为什么这不会引发“模棱两可的列”异常。(显然,这对 MySQL 来说并不模棱两可,并且 MySQL 正在确定引用哪个 ItemId,很有可能它不是您想要的。

此外,您的查询包括对行源的ItemStuff引用,但您的查询中没有显示这样的行源。

我还怀疑 that 的行为GROUP BY会给你一个不符合你期望的结果集。(现在,它很可能掩盖了查询中的真正问题,这可能是CROSS JOIN您不打算进行的操作。

我建议您尝试不使用该GROUP BY子句的查询,并确认结果集是您在没有 GROUP BY 子句的情况下所期望的。

注意:大多数其他关系数据库引擎会抛出一个异常,GROUP BY就像您在查询中显示的那样。他们(基本上)要求 SELECT 列表中的每个非聚合都包含在GROUP BY. 您可以让 MySQL 以相同的方式运行(使用某些特定的 sql_mode 设置)。MySQL 更加自由,但是您返回的结果集可能不符合您的期望。

注意:鉴于对不存在的行源的引用,我看不到此查询如何通过语义检查,并且根本没有返回任何结果集ItemStuff


为了提高可读性,我建议您不要使用逗号作为连接运算符,而是使用 JOIN 关键字。我还建议您将连接谓词从WHERE子句移动到ON子句。我还喜欢为每个行源指定一个别名,并使用该别名来限定其中的列。

鉴于您在查询中显示的内容,我会这样写(我可以理解的部分):

SELECT i.ItemID
     , i.name
     , i.price
     , d.percentOff
     , d.dollarOff
     , a.ColorName
  FROM Items i 
  JOIN ItemAttributes a
    ON a.ItemID = i.ItemID
  LEFT 
  JOIN ItemDiscounts d
    ON d.ItemID = i.ItemID
       AND ( d.percentOff > 0 OR d.dollarOff > 0 )

我已经ItemStuff.StuffID从 SELECT 列表中省略了,因为我没有看到任ItemStuff何行源。

我还排除了 WHERE 子句,因为我ItemStuff在您的查询中看不到任何行源。

-- WHERE ItemStuff.ItemID = i.ItemID

我省略了 GROUP BY,因为我在您的查询中没有看到任何 ItemStuff 行源,并且因为 GROUP BY 的行为可能不是我所期望的,而是掩盖了我的查询中的问题。

-- GROUP BY ItemStuff.StuffID

更新:

@Kyle,您的查询“超时”这一事实使我相信您生成的行比预期的要多,就像您拥有笛卡尔积一样(表中的每一行都与其他表中的每一行“匹配”。 .. 一个表中有 10,000 行,另一个表中有 10,000 行,这将生成 100,000,000 行。

我认为该GROUP BY条款掩盖了真正的问题。

对于开发,我建议您将每个表的 PRIMARY KEY 作为结果集中的前导列。我会在驱动表中添加一些合理的谓词(例如i.ItemID IN (2,3,5,7),限制结果集的大小,并按主键排序......这应该可以帮助您识别意外的笛卡尔积。

于 2012-07-24T18:48:39.353 回答
0

当你从查询中删除这些行时,你得到了你想要的吗?

AND(ItemDiscounts.percentOff > 0 或 ItemDiscounts.dollarOff > 0)

于 2012-07-24T18:37:03.917 回答
0

一旦为外连接的可能为空的一侧指定了绝对值,您的WHERE子句就必须考虑到它。

尝试使用以下子句:

AND (
ItemDiscounts.percentOff > 0
OR ItemDiscounts.percentOff is null
OR ItemDiscounts.dollarOff > 0
OR ItemDiscounts.dollarOff is null
)

另外,您指定的是GROUP BY没有聚合的 a 。在大多数情况下,这没有任何意义。你可能想要ORDER BY排序。

于 2012-07-24T18:46:07.853 回答