![](/img/trans.png)
[英]Searching comma related value with FIND_IN_SET with multiple search string Codeigniter
[英]How to compare multiple value in comma separated string using IN, FIND_IN_SET?
我有逗號分隔的多個值
(1,3,5)想與(2,3,4,5,7,5)進行比較,這個集合指的是列值。 所以它應該返回3和5
這個值是動態的
我用過
SELECT * FROM table WHERE FIND_IN_SET('3', ('2,3,4,5,7,5')) AND FIND_IN_SET('5', ('2,3,4,5,7,5'))
等等
但它非常tedius讓我知道任何更好的解決方案。
簡短的回答
你應該避免這種情況。 雖然它實際上可以完成,但您當前的架構至少違反了第一個NF 。 這是不好的情況。 存儲分隔符分隔列表僅在您需要處理整個字符串時才適用,但不適用於單獨的值本身。 因此,最合適的解決方案是:創建附加表並將值放在那里。
答案很長
這可以被視為某種謎題 - 但我強烈建議不要在實際應用中使用它。 所以,我們假設我們有表t
:
+------+------------------+ | id | col | +------+------------------+ | 1 | 1,35,61,12,8 | | 4 | 82,12,99,100,1,3 | | 6 | 35,99,1 | +------+------------------+
我們希望用字符串'1,3,35'
我們的字符串'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
( 這里有演示版)。
這個怎么運作
有一些技巧,用於此SQL。 首先,迭代變量。 MySQL支持用戶定義的變量 ,它們可用於查詢中的某種迭代。 我們正在使用它將有效的偏移量和長度傳遞給我們的字符串 - 通過SUBSTR()
得到它的一部分。
下一招:我們需要產生一定數量的行 - 否則迭代將無效。 這可以通過以下方式完成:計算每行中的分隔符並使用該計數+ 1重復它。 MySQL沒有序列,但還有第三個技巧:通過巨大的CROSS JOIN
創建所需的計數(功率總和為2
以得到連續的數字)。 那是內部LEFT JOIN
內容。 事實上,我在一個問題中遇到過這個問題。
最后,我們對整個結果進行INNER JOIN
以獲得相交的值。 注意:這是你需要為你的字符串做一些准備的部分。 但是在應用程序中拆分字符串很容易,在上面獲取所需的UNION ALL
部分查詢。
什么是不可能的
'1,,,,4,5'
這樣的事情進行檢查。 真的 - 這不是這種方法的意圖 0..9
(那個巨大的REPLACE
部分) - 我們不能動態地做到這一點 - MySQL不能“替換任何字符,除了......”這是一個瓶頸,是的 - 但是,再次 - 不是意圖方法 雖然我不建議在實時代碼中執行此操作,但可以在不需要變量的情況下完成: -
SELECT id, some_col, GROUP_CONCAT(DISTINCT SUBSTRING_INDEX(SUBSTRING_INDEX('1,3,5', ',', AnInt), ',', -1) ORDER BY 1) AS anItem
FROM some_table
CROSS JOIN
(
SELECT 1 + Units.i + Tens.i * 10 as AnInt
FROM
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Units,
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) Tens
) Sub1
WHERE FIND_IN_SET(SUBSTRING_INDEX(SUBSTRING_INDEX('1,3,5', ',', AnInt), ',', -1), some_col)
GROUP BY id, some_col
這樣做是選擇0到9聯合,並加入它自己。 這得到100個組合,並通過一點乘法得到數字0到100.然后將其與要檢查的表交叉連接,並使用此數字作為SUBSTRING_INDEX的參數將其拆分為逗號。 因此,它可以處理您要檢查的逗號分隔字符串中的~100個數字。 缺點是它會復制其中一些數字,因此需要刪除重復數據。
然后,結果數字可以與FIND_IN_SET()一起使用,以在逗號分隔字段中檢查包含這些數字的行。
然后我使用帶有DISTINCT的GROUP_CONCAT來顯示該行的匹配數字。
這里的SQL小提琴: -
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.