我有一个包含3列的表格。前两列是ID(主键)和国家/地区。第三列包含一些由冒号字符分隔的名称。例如:
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中找到了一个split函数,可以将字符串拆分。但是如何将数据拆分成多行?
答案 0 :(得分: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
钽哒!
请注意,如果这是一个高性能应用程序或使用大型表,那么在应用程序代码中执行此数据转换可能是有意义的。至少尝试规范化您的数据,这样您每次想要查看此信息时都不需要运行此代码。
答案 1 :(得分: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
您的语法可能因您的分组/解析功能而异。