这是我倾向于使用:
IF EXISTS (
SELECT 1
FROM dbo.sysobjects
WHERE id = object_id(N'[dbo].[ParseString]')
AND xtype in (N'FN', N'IF', N'TF'))
BEGIN
DROP FUNCTION [dbo].[ParseString]
END
GO
CREATE FUNCTION dbo.ParseString (@String VARCHAR(8000), @Delimiter VARCHAR(10))
RETURNS TABLE
AS
/*******************************************************************************************************
* dbo.ParseString
*
* Creator: magicmike
* Date: 9/12/2006
*
*
* Outline: A set-based string tokenizer
* Takes a string that is delimited by another string (of one or more characters),
* parses it out into tokens and returns the tokens in table format. Leading
* and trailing spaces in each token are removed, and empty tokens are thrown
* away.
*
*
* Usage examples/test cases:
Single-byte delimiter:
select * from dbo.ParseString2('|HDI|TR|YUM|||', '|')
select * from dbo.ParseString2('HDI| || TR |YUM', '|')
select * from dbo.ParseString2(' HDI| || S P A C E S |YUM | ', '|')
select * from dbo.ParseString2('HDI|||TR|YUM', '|')
select * from dbo.ParseString2('', '|')
select * from dbo.ParseString2('YUM', '|')
select * from dbo.ParseString2('||||', '|')
select * from dbo.ParseString2('HDI TR YUM', ' ')
select * from dbo.ParseString2(' HDI| || S P A C E S |YUM | ', ' ') order by Ident
select * from dbo.ParseString2(' HDI| || S P A C E S |YUM | ', ' ') order by StringValue
Multi-byte delimiter:
select * from dbo.ParseString2('HDI and TR', 'and')
select * from dbo.ParseString2('Pebbles and Bamm Bamm', 'and')
select * from dbo.ParseString2('Pebbles and sandbars', 'and')
select * from dbo.ParseString2('Pebbles and sandbars', ' and ')
select * from dbo.ParseString2('Pebbles and sand', 'and')
select * from dbo.ParseString2('Pebbles and sand', ' and ')
*
*
* Notes:
1. A delimiter is optional. If a blank delimiter is given, each byte is returned in it's own row (including spaces).
select * from dbo.ParseString3('|HDI|TR|YUM|||', '')
2. In order to maintain compatibility with SQL 2000, ident is not sequential but can still be used in an order clause
If you are running on SQL2005 or later
SELECT Ident, StringValue FROM
with
SELECT Ident = ROW_NUMBER() OVER (ORDER BY ident), StringValue FROM
*
*
* Modifications
*
*
********************************************************************************************************/
RETURN (
SELECT Ident, StringValue FROM
(
SELECT Num as Ident,
CASE
WHEN DATALENGTH(@delimiter) = 0 or @delimiter IS NULL
THEN LTRIM(SUBSTRING(@string, num, 1)) --replace this line with '' if you prefer it to return nothing when no delimiter is supplied. Remove LTRIM if you want to return spaces when no delimiter is supplied
ELSE
LTRIM(RTRIM(SUBSTRING(@String,
CASE
WHEN (Num = 1 AND SUBSTRING(@String,num ,DATALENGTH(@delimiter)) <> @delimiter) THEN 1
ELSE Num + DATALENGTH(@delimiter)
END,
CASE CHARINDEX(@Delimiter, @String, Num + DATALENGTH(@delimiter))
WHEN 0 THEN LEN(@String) - Num + DATALENGTH(@delimiter)
ELSE CHARINDEX(@Delimiter, @String, Num + DATALENGTH(@delimiter)) - Num -
CASE
WHEN Num > 1 OR (Num = 1 AND SUBSTRING(@String,num ,DATALENGTH(@delimiter)) = @delimiter)
THEN DATALENGTH(@delimiter)
ELSE 0
END
END
)))
End AS StringValue
FROM dbo.Numbers
WHERE Num <= LEN(@String)
AND (
SUBSTRING(@String, Num, DATALENGTH(ISNULL(@delimiter,''))) = @Delimiter
OR Num = 1
OR DATALENGTH(ISNULL(@delimiter,'')) = 0
)
) R WHERE StringValue <> ''
)
你会使用这样的:
SELECT id, pk_det, V.StringValue as userid
FROM myTable T
OUTER APPLY dbo.ParseString(T.userId) V
的UDF需要一个 '符合' 或数表,假设下面的模式:
IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Numbers')
BEGIN
CREATE TABLE dbo.Numbers
(
Num INT NOT NULL
CONSTRAINT [PKC__Numbers__Num] PRIMARY KEY CLUSTERED (Num) on [PRIMARY]
)
;WITH Nbrs_3(n) AS (SELECT 1 UNION SELECT 0),
Nbrs_2(n) AS (SELECT 1 FROM Nbrs_3 n1 CROSS JOIN Nbrs_3 n2),
Nbrs_1(n) AS (SELECT 1 FROM Nbrs_2 n1 CROSS JOIN Nbrs_2 n2),
Nbrs_0(n) AS (SELECT 1 FROM Nbrs_1 n1 CROSS JOIN Nbrs_1 n2),
Nbrs (n) AS (SELECT 1 FROM Nbrs_0 n1 CROSS JOIN Nbrs_0 n2)
INSERT INTO dbo.Numbers(Num)
SELECT n
FROM (SELECT ROW_NUMBER() OVER (ORDER BY n)
FROM Nbrs) D (n)
WHERE n <= 50000 ;
END
数字表格是您的工具集中非常有价值的补充。引用Adam Machanic:
数字表真的非常宝贵。我一直都在使用它们来处理字符串操作,模拟窗口函数,填充含有大量数据的测试表 ,消除了游标逻辑,还有许多其他 任务,如果没有它们,这将非常困难。
正在使用一个数字表格,因为我见过一些人声称? 编号向我展示另一种方式来高效地完成数字 表中的所有内容。它浪费空间吗?不。下面的脚本将在每个数据库中使用大约900 KB的磁盘空间大约 。这绝对不是 什么都没有。您最终将获得数百万甚至数十亿次的磁盘空间投资回报,因为易于开发和时间节省 。
http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/you-require-a-numbers-table.aspx
SQL的什么味道? SQLServer的? MySQL的? – MPelletier
对不起,MS SQL Server – Josh
可能重复[如何将逗号分隔值扩展为使用SQL Server 2005的单独行?](http://stackoverflow.com/questions/702968/how-do-i-expand-comma-使用sql-server-2005) – MPelletier