【问题标题】:SQL - Dynamic SQL query to convert single column string delimited with semicolon (;) to multiple columnsSQL - 用于将用分号 (;) 分隔的单列字符串转换为多列的动态 SQL 查询
【发布时间】:2015-12-31 05:48:37
【问题描述】:

动态 SQL 查询将用分号 (;) 分隔的单列字符串转换为多列。

ID           Rollcode            Rack
AA0001   99203; S9088        1350; 1350
ABB0001  99203; S9088        4123; 4123
ADA000   99203; S9088        530; 530
ADM000   99202; S9088;J2308  4516; 4516
ABD000   99203; S9088        3025; 3025

Desired Result should be:

ID    Rollcode1 Rollcode2 Rollcode3 Rack1   Rack2
AA0001  99203   S9088      Null     1350    1350
ABB0001 99203   S9088      Null     4123    4123
ADA000  99203   S9088      Null     530     530
ADM000  99202   S9088     J2308     4516    4516
ABD000  99203   S9088      Null     3025    3025

我已经尝试了 1 列,即(滚动代码)我们可以为其他列制作它

enter code here DECLARE @pivot varchar(8000) 
DECLARE @select varchar(8000) 
SELECT @pivot=coalesce(@pivot+',','')'[Rollcode'+cast`
(number+1 as varchar(10))+']'
FROM master..spt_values where type='p' and 
number<=(SELECT max(len(Rollcode)-len(replace
(Rollcode,';',''))) FROM tablename) 
SELECT @select=' select p.* 
from ( select  ID,substring(Rollcode, start+2, endPos-Start-2) as token, 
''Rollcode''+cast(row_number() over(partition by ID order by start) as 
varchar(10)) as n 
 from ( select ID, Rollcode, n as start
            , charindex('';'',Rollcode,n+2) endPos 
  from (select number as n from master..spt_values where type=''p'') num 
  cross join  
  ( 
  select  
  ID, '';'' + Rollcode +'';'' as Rollcode  
  from  tablename 
  ) m 
  where n < len(Rollcode)-1 
  and substring(Rollcode,n+1,1) = '';'') as Rollcode 
  ) pvt 
  Pivot ( max(token)for n in ('+@pivot+'))p'
  EXEC(@select)  

【问题讨论】:

  • 你能告诉我们你尝试了什么
  • 我有动态查询,它只转换一列(RollCode),但我还需要其他列(RACK)
  • 您正在获取非规范化数据并转换为更多非规范化数据,您实际上打算如何处理这些“动态”数据?
  • 如果您的条目数是可变的,或者可能未知,我建议将它们放在单独的(链接)表中(根据您的示例,您应该使用多对多关系)并使用 @ 连接它们987654321@
  • @Kris 我有一个非结构化表格的表格,即在 ID 列中有很多重复项,所以我通过将数据转换为行到列来区分,所以我得到了不同的 ID,各个列由分隔(;) 最后我将带分隔符的单列字符串转换为多列

标签: sql sql-server sql-server-2008 sql-server-2008-r2


【解决方案1】:

试试这个

declare @roll table (ID nvarchar(20),RollCode nvarchar(100),Rack Nvarchar(100))

insert into @roll
              select 'AA0001'   ,'99203; S9088'         ,'1350; 1350'
union all select 'ABB0001'  ,'99203; S9088'         ,'4123; 4123'
union all select 'ADA000'   ,'99203; S9088'         ,'530; 530'
union all select 'ADM000'   ,'99202; S9088;J2308'   ,'4516; 4516'
union all select 'ABD000'   ,'99203; S9088'         ,'3025; 3025'


 select ID, 
    PARSENAME(replace(RollCode,';','.'),1) as 'RollCode3', 
    PARSENAME(replace(RollCode,';','.'),2) as 'RollCode2',
    PARSENAME(replace(RollCode,';','.'),3) as 'RollCode1',
    PARSENAME(replace(Rack,';','.'),1) as 'Rack2',
    PARSENAME(replace(Rack,';','.'),2) as 'Rack1'

from @roll

【讨论】:

  • @Shaji: 在 Rollcode 列中我有这么多用分隔符分隔的代码,而不是使用解析名称为每个分配列名称,使用动态查询我们可以将它们转换为多个列
【解决方案2】:

首先,您需要一种方法来拆分用分号分隔的值。有各种拆分函数(一些用纯T-SQL 编写,一些用.net 编写)。

我正在使用CLR 函数来解决您的问题。它被命名为 [dbo].[fn_Utils_RegexSplitWithOrder] 并按正则表达式模式拆分值。这是.net 代码:

[SqlFunction(FillRowMethodName = "FillRowForSplitWithOrder")]
public static IEnumerable SplitWithOrder(SqlString sqlInput, SqlString sqlPattern)
{
    string[] substrings;
    List<Tuple<SqlInt64, SqlString>> values = new List<Tuple<SqlInt64, SqlString>>(); ;

    if (sqlInput.IsNull || sqlPattern.IsNull)
    {
        substrings = new string[0];
    }
    else
    {
        substrings = Regex.Split(sqlInput.Value, sqlPattern.Value);
    }

    for (int index = 0; index < substrings.Length; index++)
    {
        values.Add(new Tuple<SqlInt64, SqlString>(new SqlInt64(index), new SqlString(substrings[index])));
    }

    return values;
}

您可以查看此answer 以了解如何部署CLR 功能。您可以根据需要实现纯T-SQL 函数进行拆分。

现在,我们有了一个拆分数据的函数(我们需要存储它):

DECLARE @DataSource TABLE
(
    [ID] VARCHAR(12)
   ,[RollCode] VARCHAR(MAX)
   ,[Rack] VARCHAR(MAX)
);

INSERT INTO @DataSource ([ID], [RollCode], [Rack])
VALUES ('AA0001', '99203; S9088', '1350; 1350')
      ,('ABB0001', '99203; S9088', '4123; 4123')
      ,('ADA000', '99203; S9088', '530; 530')
      ,('ADM000', '99202; S9088;J2308', '4516; 4516')
      ,('ABD000', '99203; S9088', '3025; 3025');

IF OBJECT_ID('tempdb..#TempDataSource') IS NOT NULL
BEGIN
    DROP TABLE #TempDataSource;
END;

CREATE TABLE #TempDataSource
(
    [ID] VARCHAR(12)
   ,[Type] VARCHAR(8)
   ,[Index] INT
   ,[Value] VARCHAR(12)
);

INSERT INTO #TempDataSource ([ID], [Type], [Index], [Value])
SELECT DS.[ID]
      ,'Rollcode'
      ,RS.[index]
      ,LTRIM(RTRIM(RS.[value]))
FROM @DataSource DS
CROSS APPLY [dbo].[fn_Utils_RegexSplitWithOrder] (DS.[RollCode], ';') RS
UNION ALL
SELECT DS.[ID]
      ,'Rack'
      ,RS.[index]
      ,LTRIM(RTRIM(RS.[value]))
FROM @DataSource DS
CROSS APPLY [dbo].[fn_Utils_RegexSplitWithOrder] (DS.[Rack], ';') RS

在你的表中:

我们现在准备好动态PIVOT。请注意,我正在按您想要的方式排序列,但您可以更改 [ColumnOrder] 的计算方式:

DECLARE @DynamicTSQLStatement NVARCHAR(MAX);
DECLARE @DynamicPIVOTColumns NVARCHAR(MAX);

SELECT @DynamicPIVOTColumns = STUFF
(
    (
        SELECT ',[' + [ColumnName] + ']'
        FROM
        (
            SELECT DISTINCT CONCAT([Type], [Index])
                  ,[Index] + IIF([Type] = 'RACK', 100000, 0)
            FROM #TempDataSource
        ) DS ([ColumnName], [ColumnOrder])
        ORDER BY [ColumnOrder]
        FOR XML PATH('')
    )
   ,1
   ,1
   ,''
);

SET @DynamicTSQLStatement =
'
SELECT *
FROM
(
    SELECT [ID]
          ,CONCAT([Type], [Index])
          ,[Value]
    FROM #TempDataSource
) DS ([ID], [ColumnName], [Value])
PIVOT
(
    MAX([Value]) FOR [ColumnName] IN (' + @DynamicPIVOTColumns + ')
) PVT
';

EXEC  sp_executesql @DynamicTSQLStatement;

最后一部分给你:

它可能看起来很复杂,但事实并非如此。这是微不足道的动态PIVOT 任务。只需实现拆分值的功能就可以了。

【讨论】:

    【解决方案3】:

    提示试试这个,

    SELECT LEFT(RoleCode,CHARINDEX(';',RoleCode)-1) AS RoleCode1,
           RIGHT(RoleCode,CHARINDEX(';',RoleCode)) AS RoleCode2
    FROM tableName
    

    【讨论】:

    • 在 Rollcode 列中,我有这么多用分隔符分隔的代码,正在寻找转换为多个列的动态查询
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    • 1970-01-01
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    • 2021-05-13
    • 1970-01-01
    相关资源
    最近更新 更多