1

我正在尝试构建一个基于 PHP 的 Web 软件,但遇到了一个我不知道解决方案语法的问题。

基本上,我有两张桌子:

+-------------+     +---------------+
| Certs       |     | Clients       |
+-------------+     +---------------+
| userID      |     | eID           |
| prodID      |     | prods         |
| prodName    |     +---------------+
+-------------+

在这里,个人购买的每个产品都由他唯一的用户 ID 和产品的唯一 prodID 存储。

客户就像卖家,他们自己有不同的 ID,prods 是一串逗号分隔的产品 ID。

certs 表中的示例行如下所示:

userID  |  prodID  |  prodName
------------------------------
9000    |  42      |  Pen     
4234    |  54      |  Pencil
9000    |  54      |  Pencil

一个示例客户端行将如下所示:

eID  |  prods
-------------
595  |  42,54

现在,我需要形成一个查询,返回已购买特定卖家所有产品的所有用户 ID。

例如,对于卖家 ID 595,它应该返回 9000,因为用户 ID 9000 同时购买了 42 和 54。

为方便起见,可以修改表结构,但是由于其他技术问题,我无法创建与其卖家相关的标准化产品列表。

任何帮助将非常感激!谢谢~

注意:另一种说法是将卖家的产品列表保存在结果类型数组中。然后SELECT prodID FROM certs WHERE userID = x 最后检查 prodID 的结果数组是否包含数组 prods 的所有元素。

4

1 回答 1

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之间的连接条件来确定 CSV列表中是否存在。certsclientsprodIDprods

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,因此返回该行。userID4234被过滤掉,因为只有一行满足连接条件。

于 2012-07-23T06:18:53.047 回答