如何从MySQL中的SELECT中排除与LEFT JOIN不匹配的记录?

时间:2012-07-15 19:13:47

标签: mysql select left-join

我正在尝试让产品搜索在MySQL 5.0.88中正常运行。

基本设置:我有表A和产品

A.id
A.ean
A.styleNo
A.price
A.seller (ID e.g. 123, 456)

带有价格表的表B

B.name
B.ean
B.alt_price
B.seller

卖家可以定义可选的价格表,与进行搜索的用户匹配。我的搜索或多或少看起来像这样:

    SELECT A.styleNo, A.price, B.price
    FROM arts A
        LEFT JOIN pricelists B ON
                B.seller = A.seller 
            AND B.ean = A.ean 
            AND B.alt_price != 0
    WHERE...
    // pricelists
    AND ( B.name = "some_name" AND B.seller = "123" ) OR ( next applicable seller ) ...

因此,在LEFT JOIN之后,我将按名称和卖家的价格包含所有物品。

这可以正常工作,因为它同时选择常规价格(A)和alt_price(B),并且我可以在显示结果时检查现有的alt_price以向用户显示正确的价格。

但是如果卖家没有给他的所有产品提供 alt-price ,我现在用A的价格显示产品,而实际上我不想显示这个卖家的产品根本没有价格表(区域分类)。

因此,如果用户X有一个价格表“abc”而卖家123有500个产品,其中200个在价格表“abc”上,我只想以正确的价格显示200个产品而不是500个200。 / p>

我尝试在LEFT JOIN中使用 B.alt_price!= 0 ,但这没有用,因为那里的所有项目都有价格。

问题
有没有办法在实际搜索中执行此操作,或者我必须在结果循环中执行此操作,我并不是真的很想做。

3 个答案:

答案 0 :(得分:2)

SELECT 
    b.styleNo, b.price, a.alt_price
FROM
    pricelists a
INNER JOIN
    arts b ON a.seller = b.seller AND a.ean = b.ean
WHERE
    a.alt_price <> 0 AND
    a.name = 'name' AND
    a.seller = 123

INNER JOIN在此处执行的操作仅在sellerean字段在两个表中都匹配时返回行,因此它只会检索已过滤的价目表中的产品通过WHERE

另一方面,

LEFT JOIN将返回所有行,无论其他表中是否匹配。如果匹配,则显示第二个表中的相应值,但如果没有,则第二个表中的值为NULL,同时仍保留第一个表中的行数据。

因此,如果我们改为FROM arts a LEFT JOIN pricelists b ON ...,我们将从产品表中获取所有行,而不管价格表中是否存在匹配。如果价目表没有匹配,产品仍会显示,但价格表数据包含NULL值。

请注意,LEFT JOIN侧的表格保留了行数据,而不管{的右侧侧表格中的匹配项是什么{1}} ...因此“左”。

您可能需要查看Jeff Atwood的visual explanation of joins,了解不同LEFT JOIN类型的工作原理。

还要了解在加入后{em}评估<{1}},因此您在JOIN中指定的条件过滤将在加入发生后应用。因此,如果您希望仅在table2的行没有匹配{1}}中table1的行的所有行,则应指定WHERE

答案 1 :(得分:0)

听起来你想要一个内连接而不是外连接。内部联接仅返回连接条件成功的组合。左连接将始终为左表中的每一行返回至少一行。

要仅获得具有替代价格的产品,请执行以下操作:

SELECT A.styleNo, A.price, B.price
    FROM arts A
        INNER JOIN pricelists B ON
                B.seller = A.seller 
            AND B.ean = A.ean 
            AND B.alt_price is not null
    WHERE...

或者,您可以将AND B.alt_price is not null添加到当前查询的where子句中,但除非您的db的查询优化器接管,否则效率可能会降低。

答案 2 :(得分:0)

确定。终于找到了解决方案。

问题是,搜索将包含多个卖家,一些人使用价格表,一些人不使用价格表。

  • 如果我在价格表B上进行INNER JOIN,我将不会获得不使用价格表的卖家的产品,因为他们不会在B中有任何条目。
  • 如果我在价格表B上进行LEFT JOIN,所有条目都会有NULL或价格表B值,所以当我搜索卖家为他的某些产品使用价格表的时候,我总会得到他的全部,无论 alt_price 指定
  • 如果我尝试过滤这些不需要的记录(卖家使用价目表,排除不在其上的产品),通过在WHERE子句中添加 B.alt_price!= 0 ,我也排除在外来自卖家的所有产品都没有使用价格表。

我这样解决了: - 无论如何我不得不构建这条线:

LEFT JOIN pricelists B ON
       // dynamic construct depending on number of sellers using pricelists matched to user
            B.seller = A.seller 
        AND B.ean = A.ean 
        AND B.alt_price != 0
  • 因此,我创建了另一个变量,其中包含使用价格表且适用于此用户的所有卖家ID。看起来像这样:

    123456789 ...

  • 我将此添加到WHERE子句:

    AND(IF(A.seller IN(123,456,789 ...),B.alt_price IS NOT NULL,1))

这样,我正在检查 (a)如果记录来自适用于该用户的价格表卖方,并且
(b)如果是这种情况,那么记录在b.alt_price中不能有NULL值,该值不会出现在价格表中,因为当LEFT JOINING时,sql会向不在价格表B上的所有记录添加NULL。

那很难......