Sql 查询以检索以下数据

Sql Query to retrieve following data

我有一个包含 3 列的 table。前两列是 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 中找到了一个拆分函数,它可以拆分关于一个字符的字符串。但是如何将数据拆分成多行呢?

您可以创建一个新的 table 并使用循环 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

您的语法可能因 split/parse 函数而异。

任务是将名称拆分成各自的行,然后将这些行放入单个结果集中。

我们可以将此 QA 中的此函数用作拆分函数 (T-SQL: Opposite to string concatenation - how to split string into multiple records),因为它是一个 table 值函数,我们可以像处理任何其他形式的表格一样处理结果集数据(例如 table、视图、临时 table、table 变量等)

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 table 中的每一行调用此函数并合并结果。如果我们使用 CROSS APPLY,这实际上是一个单行,所以需要的查询就是这样:

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

哒哒!

请注意,如果这是一个高性能应用程序或使用大型 table,则在应用程序代码中执行此数据转换可能很有意义。至少尝试规范化您的数据,这样您就不需要 运行 每次要查找此信息时都使用此代码。