简答
你应该避免这种情况。虽然它实际上可以完成,但您当前的架构至少违反了first NF。这是一个糟糕的情况。仅当您需要使用整个字符串而不是单独的值本身时,才适用存储分隔符分隔的列表。因此,最合适的解决方案是:创建额外的表并将您的值放在那里。
长答案
这可以被视为某种谜题 - 但我强烈不建议在实际应用中使用它。所以,假设我们有表t:
+--------+------------------+
|编号 |上校 |
+--------+------------------+
| 1 | 1,35,61,12,8 |
| 4 | 82,12,99,100,1,3 |
| 6 | 35,99,1 |
+--------+------------------+
我们希望将字符串与字符串'1,3,35'“相交”。我假设您的字符串 来自应用程序 - 因此,您可以使用它进行一些准备工作。
最终的 SQL 将如下所示:
SELECT
resulted.id,
GROUP_CONCAT(resulted.sub) AS result
FROM
(SELECT
r.id,
TRIM(BOTH ',' FROM SUBSTR(
r.col,
@cur,
LOCATE(',', r.col, @cur+1)-@cur
)) AS sub,
@cur:=IF(
CHAR_LENGTH(r.col)=LOCATE(',', r.col, @cur+1),
1,
LOCATE(',', r.col, @cur+1)
) AS cur
FROM
(SELECT
id,
CONCAT(TRIM(BOTH ',' FROM t.col), ',') AS col,
CHAR_LENGTH(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(
REPLACE(col
, '9', '')
, '8', '')
, '7', '')
, '6', '')
, '5', '')
, '4', '')
, '3', '')
, '2', '')
, '1', '')
, '0', '')
) + 1 AS repeats
FROM t) AS r
LEFT JOIN
(SELECT
(two_1.id + two_2.id + two_4.id +
two_8.id + two_16.id) AS id
FROM
(SELECT 0 AS id UNION ALL SELECT 1 AS id) AS two_1
CROSS JOIN (SELECT 0 id UNION ALL SELECT 2 id) AS two_2
CROSS JOIN (SELECT 0 id UNION ALL SELECT 4 id) AS two_4
CROSS JOIN (SELECT 0 id UNION ALL SELECT 8 id) AS two_8
CROSS JOIN (SELECT 0 id UNION ALL SELECT 16 id) AS two_16
) AS init
ON init.id<r.repeats
CROSS JOIN
(SELECT @cur:=1) AS vars
) AS resulted
INNER JOIN
(SELECT '1' AS sub UNION ALL
SELECT '3' UNION ALL
SELECT '35'
) AS input
ON resulted.sub=input.sub
GROUP BY
resulted.id
(演示可用here)。
工作原理
有一些技巧用于此 SQL。首先,迭代变量。 MySQL 支持user-defined variables,它们可以用于查询中的某种迭代。我们使用它来将有效的偏移量和长度传递到我们的字符串中——通过SUBSTR() 获取它的一部分。
下一个技巧:我们需要生成一定数量的行 - 否则迭代将不起作用。这可以通过以下方式完成:计算每行中的分隔符并使用该计数 + 1 重复它。 MySQL 没有序列,但有第三个技巧:通过巨大的CROSS JOIN 创建所需的计数(使用2 的幂求和以获得连续的数字)。这就是内部LEFT JOIN 的意义所在。事实上,我在one 的问题中遇到过这个问题。
最后,我们对整个结果执行INNER JOIN 以获得我们的相交值。注意:这是你需要在你的弦上做一些准备的部分。但是在应用程序中拆分字符串很容易,需要UNION ALL 上面的查询部分。
出了什么问题
- 无效的字符串。不会对
'1,,,,4,5' 之类的内容进行检查。真的 - 这不是这种方法的意图
- 无效的非数字值。由于我们要替换
0..9(那个巨大的 REPLACE 部分)——我们不能动态地这样做——MySQL 不能“替换任何字符,除了..” 这是一个瓶颈,是的 - 但是,再次 - 不是该方法的意图