2015-01-06 83 views
0

我有一个3列的表。前两列是ID(主键)和国家。第三列包含由冒号字符分隔的一些名称。例如:Sql查询检索以下数据

ID Country Names 
-------------------------- 
1  USA  Mike;Bill 
2  USA  Michael;Lara;Van 
3  Italy  Kobe;Nate;Tim;Manu 

我需要编写一个SQL查询,为每个名称生成一个新行。例如,在这种情况下,输出将是

ID Country Name 
-------------------------- 
1 USA  Mike 
1 USA  Bill 
2 USA  Michael 
2 USA  Lara 
2 USA  Van 
3 Italy  Kobe 
3 Italy  Nate 
3 Italy  Tim 
3 Italy  Manu 

我该怎么做?我已经在t-sql中找到了一个可以将字符串分割成字符的分割函数。但如何将数据分成多行?

+0

第三列中的最大分隔值数是多少? –

+0

任何数字 - 超过20个。它基本上是一个变量。 – VVV

回答

2

任务是将名称拆分为自己的行,然后将这些行分配到单个结果集中。

我们可以使用这个函数从这个QA作为一个分割函数(T-SQL: Opposite to string concatenation - how to split string into multiple records),因为它是一个表值函数,我们可以使用结果集,就好像它是任何其他形式的表格数据(例如表格,视图,临时表,表变量等)

CREATE FUNCTION dbo.SplitStr(@sep char(1), @s nvarchar(512)) 
RETURNS table 
AS 
RETURN (

    WITH Pieces(pn, start, stop) AS (
     SELECT 1, 1, CHARINDEX(@sep, @s) 
     UNION ALL 
     SELECT pn + 1, stop + 1, CHARINDEX(@sep, @s, stop + 1) 
     FROM Pieces 
     WHERE stop > 0 
    ) 
    SELECT 
     pn, 
     SUBSTRING(@s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s 
    FROM 
     Pieces 
) 

然后我们需要调用这个函数在CountryNames表的每一行和合并结果。这实际上是,如果我们使用CROSS APPLY单衬,所以需要查询仅仅是这样的:

SELECT 
    CountryNames.ID, 
    CountryNames.Country, 
    Splat.s 
FROM 
    CountryNames 
    CROSS APPLY 
    dbo.SplitStr(';', CountryNames.Names) As Splat 

当当!

请注意,如果这是一个高性能应用程序或使用大型表格,那么在应用程序代码中执行此数据转换可能有意义。至少要试着规范你的数据,所以你不需要每次你想查看这些信息时都运行这些代码。

+0

好的调用,表值分割/解析函数对于这个问题要好得多。 –

0

您可以创建一个新表,并使用循环INSERT

SET NOCOUNT ON 
DECLARE @intFlag INT 
SET @intFlag = 1 
WHILE (@intFlag <= (SELECT MAX(LEN(REPLACE(Names,';',';;')) - LEN(Names)) FROM YourOldTable)) 
BEGIN 

INSERT INTO YourNewTable 
SELECT ID,Country 
     , Name = dbo.FN_PARSE([Names],';',@intFlag) 
FROM YourOldTable 
WHERE dbo.FN_PARSE([Names],';',@intFlag) IS NOT NULL 

SET @intFlag = @intFlag + 1 
END 
GO 
SET NOCOUNT OFF 

你的语法可能会因您的分流/解析功能。