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)
和value105
作为参数,结果应为:
+-----------+----------+
| 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);