Mysql 如何检测表中是否存在一组两个值?

Mysql 如何检测表中是否存在一组两个值?,mysql,sql,Mysql,Sql,我有一张表ProductCustomer 其中包含两个字段:ProductID和CustomerID 它表示哪个客户购买了哪个产品 假设它具有以下数据: +-----------+-------------+ | ProductID | CustomerID | +-----------+-------------+ | 17 | 105 | | 8 | 201 | | 17 | 123 | |

我有一张表
ProductCustomer
其中包含两个字段:
ProductID
CustomerID

它表示哪个客户购买了哪个产品

假设它具有以下数据:

+-----------+-------------+
| ProductID |  CustomerID |
+-----------+-------------+
|     17    |     105     |
|      8    |     201     |
|     17    |     123     |
|      9    |      36     |
|      5    |     950     |
|     14    |     204     |
|      8    |     116     |
|     39    |     105     |
+-----------+-------------+ 
我想通过一次查询来检测id为
17
8
12
39
的产品是否由id为
105
的客户购买
即查询以list
(17,8,12,39)
和value
105
作为参数,结果应为:

+-----------+----------+
| ProductID | isBought |
+-----------+----------+
|     17    |     1    | ---> Bought twice, once by CutomerId 105
|      8    |     0    | ---> Bought twice, none of them by CutomerId 105
|     12    |     0    | ---> Was not bought ever by any customer
|     39    |     1    | ---> Bought once, which was by CutomerId 105
+-----------+----------+ 
哪个查询可以帮助我推断这个结果集

如果这很重要,我正在使用MySQL



更新:产品表存在于具有其他权限的其他架构中。我无法在当前查询中使用它。

您可以尝试以下操作:()


分组依据,使用带大小写的总和进行计数

select ProductID, sum(case when CustomerID = 105 then 1 else 0 end)
from tablename
where ProductID in (17, 8, 12, 39)
group by ProductID

考虑以下几点

DROP TABLE IF EXISTS customer;
DROP TABLE IF EXISTS product;
DROP TABLE IF EXISTS product_customer;

CREATE TABLE product
(product_id INT NOT NULL PRIMARY KEY);

CREATE TABLE customer
(customer_id INT NOT NULL PRIMARY KEY);

CREATE TABLE product_customer
(product_id INT NOT NULL
,customer_id INT NOT NULL
,PRIMARY KEY(product_id,customer_id)
);

INSERT INTO product VALUES
(5),(8),(9),(14),(12),(17),(39);

INSERT INTO customer VALUES
(36),
(105),
(201),
(123),
(950),
(204),
(116);

INSERT INTO product_customer VALUES
(17    ,105),
(8     ,201),
(17    ,123),
(9     , 36),
(5     ,950),
(14    ,204),
(8     ,116),
(39    ,105);

SELECT p.*
     , MAX(CASE WHEN c.customer_id = 105 THEN 1 ELSE 0 END) isbought 
  FROM product p 
  LEFT 
  JOIN product_customer pc 
    ON pc.product_id = p.product_id 
  LEFT 
  JOIN customer c 
    ON c.customer_id = pc.customer_id 
 WHERE p.product_id IN(17,8,12,39)
 GROUP 
    BY p.product_id;
+------------+----------+
| product_id | isbought |
+------------+----------+
|          8 |        0 |
|         12 |        0 |
|         17 |        1 |
|         39 |        1 |
+------------+----------+

由于并非所有产品都存在于表ProductCustomer中,所以必须从表Product中选择,以获得每个请求产品的结果记录

当您现在想知道表ProductCustomer中是否存在记录时,应该使用exists

select 
  productid, 
  exists 
  (
    select * from productcustomer pc 
    where pc.productid = p.productid and pc.customerid = 105
  ) as isbought
from product p
where productid in (17, 8, 12, 39);
更新:由于无法访问产品表,因此必须生成要显示的记录。例如:

select 
  productid, 
  exists 
  (
    select * from productcustomer pc 
    where pc.productid = p.productid and pc.customerid = 105
  ) as isbought
from 
(
  select 17 as productid union all 
  select 8               union all 
  select 12              union all  
  select 39
) p;

更新:添加了一个查询,该查询无需在客户端进行任何额外编码即可获得所需的结果

原始答案 对于这样一个简单的任务来说,子查询和分组是太多的工作了

此查询:

SELECT DISTINCT ProductID
FROM Product_Customer
WHERE ProductID IN (17, 8, 12, 39)
  AND CustomerID = 105
返回客户购买的
ProductID
s列表-所需结果的
isbunded
列中
1
的行

在客户端语言上使用几行代码来填充其余部分:创建一个包含所有输入产品的列表,并将元素“
isbuy
属性初始化为零。运行查询。为查询返回的产品设置值
1

例如,使用PHP,它将如下所示:

// Input data
$productIDs = array(17, 8, 12, 39);
$customerID = 105;

// Prepare the list of products indexed by ProductID
// None of them was bought by the customer yet (this is all the information
// we have at this point; it will be updated below)
$list = array_fill_keys($productIDs, 0);

// Run the query
// Assume we already have a PDO connection in $db
// In production code you should protect the query against injection
// using either quoting or, better, prepared statements.
$result = $db->query(
    'SELECT ProductID '.
    'FROM Product_Customer '.
    'WHERE ProductID IN ('.implode($productIDs).') '.
        'AND CustomerID = '.$customerID
);

// Get the values
while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
    $prodID = intval($row['ProductID']);
    // Mark the product as bought
    $list[$prodID] = 1;
}

// Dump $list to check the outcome
print_r($list);
使现代化 通过使用表
Products
(FK`ProductID来自的表),可以直接从数据库中检索所需的结果:

如果表
Products
不可用(OP在问题中添加了此额外条件),则需要不知何故生成包含所有所需
ProductID
s的结果集

一种可能性是
在单独的查询中选择每个值,然后
联合它们:

SELECT DISTINCT p.ProductID, IF(pc.ProductID IS NULL, 0, 1) AS isBought
FROM Product_Customer pc
  RIGHT JOIN (
    SELECT 17 AS ProductID
    UNION
    SELECT 8 AS ProductID
    UNION
    SELECT 12 AS ProductID
    UNION
    SELECT 39 AS ProductID
  ) p ON pc.ProductID = p.ProductID AND pc.CustomerID = 105
我们不再需要
WHERE
条件,因为我们动态生成的伪
Products
表(使用
UNION
)只包含
ProductID
的所需值,没有其他内容)

它并不比原始查询慢(请参阅第一个查询,它只返回
Product\u Customer
表中存在的产品),而且我认为它比
JOIN
s真正的
产品
表快



另一个解决方案(更为深奥但有效)是由。

以下内容涉及表中不存在product#12这一事实,但假设您的表中已经有一些行

  SET @a:=0.5;
  SELECT @b:=MAKE_SET(@a:=@a*2, 17,8,12,39) ProductID,
     IFNULL((SELECT 1 FROM mytable2
     WHERE ProductID=@b AND CustomerID=105 LIMIT 1), 0) isBought
     FROM mytable2 m1
     LIMIT 4;

 +-----------+----------+
 | ProductID | isBought |
 +-----------+----------+
 | 17        |        1 |
 | 8         |        0 |
 | 12        |        0 |
 | 39        |        1 |
 +-----------+----------+
当然,如果您有一个产品表,您只需执行以下操作:

 SELECT p.ProductID, IFNULL((SELECT 1 FROM mytable2
    WHERE ProductID=p.ProductID AND CustomerID=105 LIMIT 1), 0) isBought
 FROM Products p
 WHERE p.ProductID IN(17,8,12,39);

因此,还有一个产品表,其中包含所有产品ID?您需要一个包含此表中缺少的
ProductID
s的表,以便从某处选择它们。对于其他
RDBMS
-es来说,从任何地方生成数据都是一件容易的工作,但是对于MySQL来说,这并不是一件很容易的工作。这并没有给出正确的输出。它跳过了从未被任何客户购买过的产品(例如产品12)@YotamOmer。非常奇怪,它选择ProductID为(17、8、12、39)的所有行,并计算CustomerID=105的行数。@jarlh:一点也不奇怪。ProductCustomer中还没有产品12的记录。@ThorstenKettner,现在我明白了!(没有注意到产品不存在。)+1表示正确:)我也更新了我的答案来支持这一点。你为什么在这里使用连接?@YotamOmer嗯,为什么不?如果性能是个问题,那么我怀疑axiac的解决方案会打击您和我;-)产品表存在于具有其他权限的其他架构中。我不能在当前查询中使用它,是的,我认为这是一个合理的方法,如果应用程序代码是可用的,但我不认为这不太管用。程序员的工作更多,应用程序的工作更多,网络的工作也更多。但无可否认,DBMS的工作量更少。@ThorstenKettner,网络的工作量更少。它是单个列,只是预期行的子集。程序员额外的工作量在很大程度上取决于客户端语言。脚本语言通常可以在一行代码中创建所需的数据结构并用零填充(在上面的PHP代码中调用函数
array\u fill\u keys()
)。代码的其余部分已经在那里,准备好获取和处理从数据库接收到的结果集。把它们放在一起,客户端应用程序和数据库,总的来说工作量就更少了。@axiac。考虑客户购买产品数千次的日常购买。您将从数据库中检索数千条记录,而不是检索四条记录。这是我认为更多的工作为网络。至于应用程序:是的,这取决于所使用的语言。例如,在C#中,我可以用两行代码将结果集填充到一个数据集,或者在循环中手动填充数据集。@AshrafBashir我用另一个查询(实际上是两个查询)更新了答案,该查询直接从数据库获得所需的结果集,而不需要在客户端进行额外的编码。如果
Products
表不可访问,那么我建议使用另一种查询,当l
  SET @a:=0.5;
  SELECT @b:=MAKE_SET(@a:=@a*2, 17,8,12,39) ProductID,
     IFNULL((SELECT 1 FROM mytable2
     WHERE ProductID=@b AND CustomerID=105 LIMIT 1), 0) isBought
     FROM mytable2 m1
     LIMIT 4;

 +-----------+----------+
 | ProductID | isBought |
 +-----------+----------+
 | 17        |        1 |
 | 8         |        0 |
 | 12        |        0 |
 | 39        |        1 |
 +-----------+----------+
 SELECT p.ProductID, IFNULL((SELECT 1 FROM mytable2
    WHERE ProductID=p.ProductID AND CustomerID=105 LIMIT 1), 0) isBought
 FROM Products p
 WHERE p.ProductID IN(17,8,12,39);