我正在尝试构建基于PHP的Web软件,我遇到了一个我不知道解决方案语法的问题。
基本上,我有两张桌子:
+-------------+ +---------------+
| Certs | | Clients |
+-------------+ +---------------+
| userID | | eID |
| prodID | | prods |
| prodName | +---------------+
+-------------+
此处,个人购买的每件商品都由其唯一的用户ID和产品的独特产品存储。
客户就像是卖家,他们自己拥有不同的ID,而且是一串逗号熟练的产品ID。
certs表中的示例行如下:
userID | prodID | prodName
------------------------------
9000 | 42 | Pen
4234 | 54 | Pencil
9000 | 54 | Pencil
示例客户行如下:
eID | prods
-------------
595 | 42,54
现在,我需要形成一个查询,返回已购买特定卖家所有产品的所有用户ID。
例如,对于卖家ID 595,它应该返回9000,因为userID 9000已经购买了42和54.
为方便起见,可以修改表格结构,但由于其他技术原因,我无法创建与其卖家相关的标准化产品列表。
任何帮助将不胜感激!感谢〜
注意:另一种方法是将卖家的产品列表保存在结果类型数组中。 然后 SELECT prodID FROM 证书 WHERE userID = x 最后检查是否,prodID的结果数组包含数组prods的所有元素。
答案 0 :(得分:2)
试试这个解决方案:
SELECT a.userID
FROM certs a
INNER JOIN clients b ON b.eID = 595 AND FIND_IN_SET(a.prodID, b.prods) > 0
CROSS JOIN
(
SELECT (LENGTH(prods) - LENGTH(REPLACE(prods, ',', ''))) + 1 AS prodcnt
FROM clients
WHERE eID = 595
) c
GROUP BY a.userID, c.prodcnt
HAVING COUNT(1) = c.prodcnt
CROSS JOIN
(
SELECT (LENGTH(prods) - LENGTH(REPLACE(prods, ',', ''))) + 1 AS prodcnt
FROM clients
WHERE eID = 595
) c
这样做会在每一行附加特定卖家拥有的prodID数量。我们通过获取CSV列表的字符串长度并减去相同CSV列表的长度但没有逗号来计算它,并在差异中添加一个。例如:
字符串长度“54,234,436
”为10。
替换逗号:
字符串长度“54234436
”为8。
那么(10-8)+1 = 3。
列表中的三个项目。
我们使用FIND_IN_SET
作为certs
和clients
之间的联接条件,以确定prodID
列表中是否存在prods
。
FIND_IN_SET
基本上返回CSV列表中特定项目的从1开始的索引位置。例如:
FIND_IN_SET('54', '34,76,54,128')
将返回3
,因为54
作为列表中的第三项存在。我们只需要检查它是否存在于连接条件的列表中,所以我们只检查它是否是> 0.如果该项目不在CSV列表中,则返回0.
一旦我们有特定客户的产品与笛卡尔联合计数,并且加入了表,中间结果集将如下所示:
a.userID | a.prodID | b.eID | b.prods | c.prodcnt
---------------------------------------------------------
9000 | 42 | 595 | 42,54 | 2
4234 | 54 | 595 | 42,54 | 2
9000 | 54 | 595 | 42,54 | 2
这些行中的每一行都满足连接条件。
然后我们按userID
进行分组,以计算每userID
行的行数。由于9000与c.prodcnt
中的重复值具有相同的行数,因此返回该行。 userID 4234
是适合的,因为只有一行满足连接条件。