2010-06-17 51 views
1

我有一个相当简单的要求 - 我有一个表,其中包含以下(相关)结构。SQL Server 2008每行分割字符串变量令牌数

with cte as(
select 1 id,'AA,AB,AC,AD' names union all 
select 2,'BA,BB' union all 
select 3,'CA,CB,CC,CD,CE' union all 
select 4,'DA,DB,DC' 
) 

我想创建一个select语句,将每个“名称”列拆分为多行。

例如第一行应该产生

1,'AA' 
1,'AB' 
1,'AC' 
1,'AD' 

我们能做到这一点只使用SQL。这在Oracle中很容易实现。

+0

它通常是不透明的查询,但逗号是分开的d列表确实使情况复杂化。理想情况下,您应该更正数据模型,以便在单个列值中不包含用逗号分隔的值。 – 2010-06-17 20:44:43

回答

2

您可以没有任何自定义的功能做在一个查询,如果你利用XML:

WITH cte AS(/*your data*/ 
    SELECT 1 id,'AA,AB,AC,AD' names UNION ALL 
    SELECT 2,'BA,BB' UNION ALL 
    SELECT 3,'CA,CB,CC,CD,CE' UNION ALL 
    SELECT 4,'DA,DB,DC' 
) 
, xmlData AS (/*make into xml*/ 
    SELECT id, cast('<root><x>'+replace(names,',','</x><x>')+'</x></root>' as xml) AS theXML 
    FROM cte 
) 
SELECT id, x.value('.','varchar(100)') /*split up*/ 
FROM xmlData 
CROSS APPLY xmlData.theXML.nodes('//x') AS func(x) 
+0

请注意,如果您的名称超过100个字符,则转换为varchar时必须具有更大的长度。除了2008年,这也将在SQL Server 2005上运行。 – Zugwalt 2010-06-17 20:59:25

1

您可以创建一个返回表的分割函数,然后从该表中选择。

/*************************************************************************** 
** 
** Function: split 
** In: @ipRowData - The delimited list of items to split. 
** In: @ipSplitOn - The delimiter which separates the items in @rowData. 
** Returns: A table object containing the split items. The table object 
** will have an ID and Data column, where ID is the number of the item 
** in the original list and Data is the value of the item. 
** 
** Description: 
** Splits a delimited set of items and returns them 
** as a table object. 
***************************************************************************/ 
CREATE FUNCTION [dbo].[split] 
(
    @ipRowData NVARCHAR(4000), 
    @ipSplitOn NVARCHAR(5) 
) 
RETURNS @rtnValue table 
(
    ID INT identity(1,1), 
    Data NVARCHAR(100) 
) 
AS 
BEGIN 
    DECLARE 
     @cnt INT 
     Set @cnt = 1 

    WHILE (Charindex(@ipSplitOn,@ipRowData)>0) 
    BEGIN 
     INSERT INTO @rtnValue 
       (data) 
        SELECT Data = ltrim(rtrim(Substring(@ipRowData,1,Charindex(@ipSplitOn,@ipRowData)-1))) 
     SET @ipRowData = Substring(@ipRowData,Charindex(@ipSplitOn,@ipRowData)+1,len(@ipRowData)) 
     SET @cnt = @cnt + 1 
    END 

    INSERT INTO @rtnValue (data) 
    SELECT DATA = ltrim(rtrim(@ipRowData)) 

    RETURN 
END 

GO 

用法示例:

select 1,data from [dbo].split('AA,AB,AC,AD', ','); 

输出:

(No column name) data 
1     AA 
1     AB 
1     AC 
1     AD