我有一张桌子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
的客户购买。
即查询将列表(17, 8, 12, 39)
和值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。
更新:产品表存在于具有其他权限的另一个模式中。我无法在当前查询中使用它。
答案 0 :(得分:1)
更新添加了一个获得所需结果的查询,无需在客户端进行任何额外编码。
子查询和GROUP BY
对于这么简单的任务来说太过分了。
此查询:
SELECT DISTINCT ProductID
FROM Product_Customer
WHERE ProductID IN (17, 8, 12, 39)
AND CustomerID = 105
会向您返回客户购买的ProductID
列表 - 您所需结果的1
列中包含isBought
的行。
在客户端语言上使用几行代码来填充其余部分:创建一个包含所有输入产品的列表并初始化元素' isBought
属性为零。运行查询。为返回的产品设置值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);
可以通过JOIN
- 表Products
(FK
`ProductID来自的表)直接从数据库中检索所需的结果:
SELECT DISTINCT p.ProductID, IF(pc.ProductID IS NULL, 0, 1) AS isBought
FROM Product_Customer pc
RIGHT JOIN Products p ON pc.ProductID = p.ProductID AND pc.CustomerID = 105
WHERE p.ProductID IN (17, 8, 12, 39)
如果表Products
不可用(OP在问题中添加了这个额外条件),则需要以某种方式无处生成包含所有所需ProductID
的结果集。
一种可能性是SELECT
单独查询中的每个值UNION
:
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
的所需值{1}}并没有别的。)
它并不比原始查询慢(请参阅第一个查询,即仅返回Product_Customer
表中存在的产品的查询),我认为它比JOIN
的查询更快是真正的Products
表。
this answer揭示了另一种解决方案(更深奥但更有效)。
答案 1 :(得分:0)
您可以尝试以下操作:(Working SQLFiddle)
SELECT
ProductID,
(SELECT COUNT(*) FROM ProductCustomer AS p2 WHERE CustomerID=105 AND p1.ProductID=p2.ProductID) AS isBought
FROM Product AS p1
WHERE ProductID IN (17, 8, 12, 39)
答案 2 :(得分:0)
考虑以下内容......
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 |
+------------+----------+
答案 3 :(得分:0)
由于并非所有产品都存在于表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;
答案 4 :(得分:0)
以下说明产品#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);
答案 5 :(得分:-1)
GROUP BY,使用SUM计算大小写
select ProductID, sum(case when CustomerID = 105 then 1 else 0 end)
from tablename
where ProductID in (17, 8, 12, 39)
group by ProductID