2015-01-06 108 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 

你的語法可能會因您的分流/解析功能。