SQL将列的值与其他列的所有值EXCEPT值匹配

时间:2016-03-18 20:25:08

标签: mysql

我只有一个表:产品

ID | Product Name | Code 1 | Code 2 | Code 3
********************************************
1  |    Phone1    |   MM   |   DD   |   nd
2  |    Phone2    |   DD   |        |   nd
3  |    Phone3    |   MM   |   ZZ   |   nd
4  |    Phone4    |   XX   |        |   nd

我想:

  

选择其中一个代码与其中一个匹配的所有手机    Phone1 的代码但如果代码= ND

因此它应该返回 Phone2 Phone3 ,但现在它将全部返回。

SQL Fiddle(感谢@JamieD77

我认为我应该使用这样的东西?但是不能正确地放置它:

 WHERE NOT EXISTS 
 (SELECT p1.`Product Name` 
 FROM `products` p1 
 WHERE
 p.`Product Name` = 'nd')

我相信在查找匹配项时,可以让MySQL更简单地排除每列中的某些值。

1 个答案:

答案 0 :(得分:1)

让我们先回到“Phone1'”。我们可以轻松获得id值,因此我们可以使用它。我们还可以使用product_name列。

 SELECT p.id
      , p.product_name
      , p.code_1
      , p.code_2
      , p.code_3
   FROM products p
  WHERE p.id = 1

很容易。

现在找到带有"匹配"的手机码。我们可以从加入products表开始。

Phone1将在其中一个代码上匹配。 (假设至少有一个非NULL和非 - '代码。)我们假设我们不想返回Phone1,所以我们可以排除在连接谓词中...仅返回id值不同的行。

要查找匹配代码,我们可以将候选手机中的code_1与Phone1的code_1,code_2和code_3进行比较,看看其中任何一个是否相同。我们可以为候选电话的code_2和code_3做同样的事情。

规范确实告诉我们nd不会被视为匹配代码,因此我们可以快速进行比较,如果我们进行比较的code_N等于' nd'

从规范中,我们不清楚是否要考虑空字符串或空白,以等于空白或空字符串的另一个代码。 (我们无法判断这些空代码是否为NULL值,零长度字符串或空格。)

而且,显然,我们想要从"匹配"中返回列。电话,而不是Phone1行。

这样的事情可以解决问题:

 SELECT o.id
      , o.product_name
      , o.code_1
      , o.code_2
      , o.code_3
   FROM products p
   JOIN products o
     ON o.id <> p.id 
    AND (  (o.code_1 <> 'nd' AND o.code_1 IN (p.code_1,p.code_2,p.code_3) ) 
        OR (o.code_2 <> 'nd' AND o.code_2 IN (p.code_1,p.code_2,p.code_3) )
        OR (o.code_3 <> 'nd' AND o.code_3 IN (p.code_1,p.code_2,p.code_3) )
        )
  WHERE p.id = 1

使用连接谓词中的条件,o.code_N中的NULL值不会与p.code_N中的NULL值匹配。如果我们也想忽略空字符串的匹配,我们可以稍微调整一下条件:

    AND (  (o.code_1 NOT IN ('nd','') AND o.code_1 IN (p.code_1,p.code_2,p.code_3) ) 
        OR (o.code_2 NOT IN ('nd','') AND o.code_2 IN (p.code_1,p.code_2,p.code_3) )
        OR (o.code_3 NOT IN ('nd','') AND o.code_3 IN (p.code_1,p.code_2,p.code_3) )
        )

在表现方面,这可能不会赢得任何比赛。

这不是唯一会返回指定结果的查询模式。我们可以编写一个使用EXISTS子句的查询来完成同样的事情:

 SELECT o.id
      , o.product_name
      , o.code_1
      , o.code_2
      , o.code_3
   FROM products o
  WHERE EXISTS 
        ( SELECT 1
           FROM phones p
          WHERE p.id = 1
            AND o.id <> p.id
            AND (  (o.code_1 <> 'nd' AND o.code_1 IN (p.code_1,p.code_2,p.code_3) ) 
                OR (o.code_2 <> 'nd' AND o.code_2 IN (p.code_1,p.code_2,p.code_3) )
                OR (o.code_3 <> 'nd' AND o.code_3 IN (p.code_1,p.code_2,p.code_3) )
                )
        )

如果有适当的索引,我们可以重写(可能)更高效。

就更简单的事情而言,如果电话的Code 1Code 2Code 3在另一个表中存储为单独的行,则SQL的编写方式会有所不同:

phone_code

phone_id  code_num  code_val
       1         1  MM
       1         2  DD
       1         3  nd
       2         1  DD
       2         2  
       2         3  nd
       3         1  MM
       3         2  ZZ
       3         3  nd
       4         1  XX
       4         2  
       4         3  nd

如果数据的结构是这样的,那么SQL代码就会有所不同。