我有下一个表,如何获得点(。)特殊字符前后的子字符串?
MyTable
------------------------------
Id Description
------------------------------
1 [Hugo].[date].[Subtotal]
2 [Juan].[date].[Subtotal]
3 [7/23/2013].[SubTotal]
4 [7/25/2013].[Total]
我正在寻找以下结果
MyResultTable
------------------------
MyTableId Description depth
-----------------------
1 [Hugo] 1
1 [date] 2
1 [Subtotal] 3
2 [Juan] 1
2 [date] 2
2 [Subtotal] 3
3 [7/23/2013] 1
3 [SubTotal] 2
4 [7/25/2013] 1
4 [Total] 2
我想将点(。)后面的单词分开,并将单词列为下表 我该如何解决?
答案 0 :(得分:2)
您需要根据.
拆分数据。您可以使用递归CTE分割数据并返回深度:
;with cte (id, DescriptionItem, Description, depth) as
(
select id,
cast(left(Description, charindex('.',Description+'.')-1) as varchar(50)) DescriptionItem,
stuff(Description, 1, charindex('.',Description+'.'), '') Description,
1 as depth
from MyTable
union all
select id,
cast(left(Description, charindex('.',Description+'.')-1) as varchar(50)) DescriptionItem,
stuff(Description, 1, charindex('.',Description+'.'), '') Description,
depth+1
from cte
where Description > ''
)
select id, DescriptionItem, depth
from cte
order by id, depth;
或者您可以使用分割数据的UDF函数:
create FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))
returns @temptable TABLE (items varchar(MAX), depth int)
as
begin
declare @idx int
declare @slice varchar(8000)
declare @depth int = 1
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Items, depth) values(@slice, @depth)
set @String = right(@String,len(@String) - @idx)
set @depth = @depth +1
if len(@String) = 0 break
end
return
end;
然后,当您调用该函数时,您将使用与此类似的CROSS APPLY
:
select t.id, c.items description,
c.depth
from mytable t
cross apply dbo.split(t.description, '.') c
order by t.id, c.depth;
答案 1 :(得分:1)
USE tempdb;
GO
IF OBJECT_ID('dbo.csv_split','U') IS NOT NULL DROP TABLE dbo.csv_split;
CREATE TABLE dbo.csv_split
(
Id INT NOT NULL PRIMARY KEY
,Description VARCHAR(100)
)
INSERT INTO dbo.csv_split(Id,Description)
VALUES
(1,'[Hugo].[date].[Subtotal]')
,(2,'[Juan].[date].[Subtotal]')
,(3,'[7/23/2013].[SubTotal]')
,(4,'[7/25/2013].[Total]');
WITH cte_xml AS
(
Select csv.Id
,CONVERT(XML,'<desc>'
+ REPLACE(csv.Description,'.','</desc><desc>')
+ '</desc>') AS xml_desc
From dbo.csv_split csv
)
,cte_shred_xml AS
(
Select t.Id
,xml_desc_nodes.value('(.)','varchar(50)') AS Description
,ROW_NUMBER() OVER(PARTITION BY t.Id ORDER BY t.Id ) AS Depth
From cte_xml t
CROSS APPLY t.xml_desc.nodes('/desc') AS t2(xml_desc_nodes)
)
Select *
From cte_shred_xml
答案 2 :(得分:0)
这是一个简单的例子。我创建了你的表为@test并在游标中使用了游标和循环。
DECLARE @test TABLE ( id INT, NAME VARCHAR(MAX) )
INSERT @test
VALUES ( 1, '[Hugo].[date].[Subtotal]' )
INSERT @test
VALUES ( 2, '[Juan].[date].[Subtotal]' )
INSERT @test
VALUES ( 3, '[7/23/2013].[SubTotal]' )
INSERT @test
VALUES ( 4, '[7/25/2013].[Total]' )
DECLARE @id INT ,
@name VARCHAR(MAX)
DECLARE @values TABLE
(
MyTableId INT ,
Description VARCHAR(MAX) ,
Depth INT
)
DECLARE @v VARCHAR(2000) ,
@i INT ,
@depth INT
DECLARE @MyTableList CURSOR
SET
@MyTableList = CURSOR FOR SELECT id, name FROM @test
OPEN @MyTableList
FETCH NEXT FROM @MyTableList INTO @id, @name
WHILE @@FETCH_STATUS = 0
BEGIN
SET @depth = 1
SET @i = PATINDEX('%.%', @name)
WHILE @i > 0
BEGIN
INSERT @values
VALUES ( @id, SUBSTRING(@name, 1, @i - 1), @depth )
SET @name = SUBSTRING(@name, @i + 1, LEN(@name) - @i)
SET @i = PATINDEX('%.%', @name)
SET @depth = @depth + 1
END
INSERT @values
VALUES ( @id, @name, @depth )
FETCH NEXT FROM @MyTableList INTO @id, @name
END
SELECT MyTableId ,
Description ,
Depth
FROM @values
您的输出应该如下所示。
MyTableId Description Depth
1 [Hugo] 1
1 [date] 2
1 [Subtotal] 3
2 [Juan] 1
2 [date] 2
2 [Subtotal] 3
3 [7/23/2013] 1
3 [SubTotal] 2
4 [7/25/2013] 1
4 [Total] 2