给定以下代表可能列表的字符串,我如何在指定索引处获取项目n
1,2,3,4,5
word1 word2 word3
pipe|delimited|list
此功能的可能原因是
- 从 GROUP_CONCAT 输出中提取特定元素
- 从 SET 列输出中提取特定元素(转换为字符串时)
- 从包含逗号分隔列表的不良规范化表中提取特定元素
- 在迭代过程中使用循环遍历列表并对其中的每个元素执行操作
给定以下代表可能列表的字符串,我如何在指定索引处获取项目n
1,2,3,4,5
word1 word2 word3
pipe|delimited|list
此功能的可能原因是
没有本机功能。您可以使用两个 SUBSTRING_INDEX 函数。您需要检查该特定索引项是否存在:
SET @string:='1,2,3,4,5';
SET @delimiter:=',';
SET @n:=6;
SELECT
CASE WHEN
CHAR_LENGTH(@string)-CHAR_LENGTH(REPLACE(@string, @delimiter, ''))>=
@n*CHAR_LENGTH(@delimiter)-1
THEN
SUBSTRING_INDEX(SUBSTRING_INDEX(@string, @delimiter, @n), @delimiter, -1)
END;
SUBSTRING_INDEX(@string, @delimiter, @n)
@string
在@n
出现@delimiter
. _SUBSTRING_INDEX( ... , @delimiter, -1)
返回最后定界符右侧的所有内容@n
存在。我们可以减去带分隔符的字符串的长度,去掉分隔符的字符串 - 使用REPLACE(@string, @delimiter, '')
- 看看是否大于@n*CHAR_LENGTH(@delimiter)-1
纯 SQL 的做法:-
SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(somefield, '|', 3), '|', -1)
FROM sometable a
如果您想在没有第三个元素(例如)的情况下返回 NULL(或其他一些固定值):-
SELECT IF((LENGTH(somefield) - LENGTH(REPLACE(somefield, '|', '')) + 1) >= 10, SUBSTRING_INDEX(SUBSTRING_INDEX(somefield, '|', 10), '|', -1), NULL)
FROM sometable a
更新完全忘记了 SUBSTRING_INDEX -1 的事情(@fthiella 和 @Kickstart 指出),所以更新了下面的例子
通过创建一个可以在线使用的存储函数来解决。存储的函数能够接受输入字符串、任何单字符分隔符以及要提取的所需项目的索引。
存储函数定义如下
CREATE DEFINER = `user`@`%`
FUNCTION `getListElement`(
inString VARCHAR(255) ,
inDelimiter CHAR(1) ,
inIndexToReturn TINYINT UNSIGNED
) RETURNS varchar(255) READS SQL DATA DETERMINISTIC SQL SECURITY INVOKER
BEGIN
-- Takes in as argument a string, and then breaks out the desired string
DECLARE resultString VARCHAR(255) DEFAULT inString;
DECLARE numberOfListElements TINYINT UNSIGNED DEFAULT 0;
DECLARE errorMessage VARCHAR(255) DEFAULT 'Requested index was < 1 which was invalid';
-- First of all, additional processing only needed for element 2 upwards
IF inIndexToReturn = 1 THEN
RETURN SUBSTRING_INDEX( resultString , inDelimiter , inIndexToReturn);
ELSEIF inIndexToReturn > 1 THEN
-- Count the number of elements
-- This will count the missing delimiters based off the replace. A list of 4 will be missing 3 characters.
SET numberOfListElements = ( CHAR_LENGTH( resultString ) + 1 ) - CHAR_LENGTH( REPLACE( resultString , inDelimiter , '' ) );
IF numberOfListElements >= inIndexToReturn THEN
-- Make sure to only return the last of the elements returend by the first SUBSTRING_INDEX
RETURN SUBSTRING_INDEX( SUBSTRING_INDEX( inString , inDelimiter , inIndexToReturn ) , inDelimiter , -1 );
END IF;
SET errorMessage = CONCAT('List index ',inIndexToReturn,' was requested from a list with ',numberOfListElements,' elements');
END IF;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = errorMessage;
END
在上面的示例中,以下内容可用于提取特定的列表元素
SELECT getListElement( '1,2,3,4,5' , ',' , 2 )
返回2
SELECT getListElement( REPLACE( 'word1 word2 word3' ,' ', ',' ) , ',' , 3 )
退货word3
(原因见下文注释REPLACE
)SELECT getListElement( 'pipe|delimited|list' , '|' , 1 )
返回pipe
也可以在迭代器中使用它来循环列表中的元素。首先,您需要计算列表中的项目(请参阅如何计算逗号分隔列表 MySQL 中的项目)但是一旦有了,只需像在存储过程中的这个片段中那样迭代它们
-- Reinitialise variables
SET @list = '1,2,3,4,5';
SET @delimiter = ',';
SET @listLength = (CHAR_LENGTH( @list ) + 1 ) - CHAR_LENGTH( REPLACE( @list , @delimiter , '' ) );
SET @currentElement = 1;
listLoop: REPEAT
-- Select the list element and do something with it
SELECT getListElement( @list , @delimiter , @currentElement );
-- Increment the current element
SET @currentElement = @currentElement + 1;
UNTIL @currentElement > @listLength
END REPEAT listLoop;
重要的以空格分隔的列表似乎会导致此过程出现问题,因此在将字符串解析为函数之前,我建议REPLACE
先用另一个合适的单字符分隔符替换空格(即,
或|
取决于字符串中的内容) )