动态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)
答案 0 :(得分: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
答案 1 :(得分:1)
首先,您需要一种方法来分割用冒号分隔的值。有各种分割函数(一些用纯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
任务。只需实现分割值的功能,你就可以了。
答案 2 :(得分:0)
提示试试这个,
SELECT LEFT(RoleCode,CHARINDEX(';',RoleCode)-1) AS RoleCode1,
RIGHT(RoleCode,CHARINDEX(';',RoleCode)) AS RoleCode2
FROM tableName