Sql Query检索以下数据

时间:2015-01-06 22:55:29

标签: sql database string tsql split

我有一个包含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函数,可以将字符串拆分。但是如何将数据拆分成多行?

2 个答案:

答案 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

您的语法可能因您的分组/解析功能而异。