数据:
COL1 COL2 COL3 DEPTH
URL1 URL2 2
URL2 URL3 2
URL3 URL4 URL5 3
URL1 URL2 URL3 3
在上面的数据中,Tree列由以“||”分隔的字符串组成。我需要转换上面的数据,以便我有3列(因为在这个例子中最大深度是3),结果应如下所示:
balance
在上面的示例中,最大深度为3,但在现实世界中,它可以是N数。
答案 0 :(得分:0)
美好的一天,
乍一看,我们需要使用用户定义的SPLIT函数,但由于每个字符串中的值的数量不超过4,因此有一个更简单,可能更好的解决方案。我们只需要使用内置的PARSENAME function。
我没有测试代码,但解决方案应该是这样的:
SELECT PARSENAME(REPLACE(Tree,'||','.'), 1) as col1, PARSENAME(REPLACE(Tree,'||','.'), 2) as col2, PARSENAME(REPLACE(Tree,'||','.'), 3) as col3, Depth
from TableName
我替换了||带点,因为PARSENAME解析按点分割的名称。这就是诀窍: - )
我在sqlsaturday #360的演讲中实际上提到了这样的例子。你可以see the presentation。讲座是关于为什么要使用SQLCLR,而不是那么重要何时使用它而不是transact-SQL。但我也谈到了什么时候不使用它,这就是那里的例子之一。
无论如何!如果你打算使用SPLIT函数,那么你应该使用SQLCLR而不是T-SQL,as you can see here。
答案 1 :(得分:0)
试试这个,您只需要输入您的输入表,输出表,分隔线和列进行拆分。与PARSENAME功能不同,它可以处理3个以上的深度。
测试了100,000条记录和30条拆分列。创建所需的输出需要10秒。
Declare @Delimiter nvarchar(10) = '||'
Declare @InputTable nvarchar(2000) = '<<input table name>>'
Declare @OutputTable nvarchar(2000) = '<<output table name>>'
Declare @ColumnToSplit nvarchar(2000) = '<<column to split>>'
Declare @lsql nvarchar(max)
Declare @treeDepth int
If Object_id('dbo.treeDepth') is not null
Drop table dbo.treeDepth
CREATE TABLE dbo.treeDepth (depth INT)
declare @ltext nvarchar(max)= 'Select max(1+(len('+@ColumnToSplit+')- len(Replace('+@ColumnToSplit+','''+@Delimiter+''','''')))/(len('''+@Delimiter+'''))) from '+@InputTable
insert dbo.treeDepth EXEC(@ltext)
Select @lsql = isnull(@lsql+',','') +
'xmlname.value(''/Node[1]/Node['+cast(number+1 as nvarchar)+']'',''varchar(1000)'') AS Col_'+cast(number+1 as nvarchar)+''
from master..spt_values where type = 'P' and number < (Select * from dbo.treeDepth)
set @lsql = '
WITH ForXML
AS
(
SELECT *,
CONVERT(XML,''<Node><Node>''
+ REPLACE('+@ColumnToSplit+','''+@Delimiter+''', ''</Node><Node>'') + ''</Node></Node>'') AS xmlname
FROM '+@InputTable+'
)
Select *, '+@lsql+' Into '+@OutputTable+' From ForXML
Alter table '+@OutputTable+'
Drop column xmlname
'
EXEC(@lsql)