问题
I have a table with several rows of data like this :
16 W:\2-Work\ALBO\00_Proposal\ALxO_Amendement #1_20091022_signed.pdf
17 W:\2-Work\ALBO\00_Proposal\Level1\ALBO_Amendment #1_20110418.docx
18 W:\2-Work\ALBO\00_Proposal\A\BR\T\X_#1_20110418_final.docx
19 W:\2-Work\ALBO\MyOptionl\AO_Amendment_2 August 2013.docx
I have created columns from Col1
to Col10
I would like to separate each value with the delimiter '\'
The idea is to have on each column :
Col1 | Col2 | Col3 | Col4 | Col5 |etc...
W: 2-Work ALBO 00_Proposal ALxO_Amendement #1_20091022_signed.pdf
I know how to use charindex
and substring
but the number of '\' are different on each line (8500 rows).
Could you help me?
I'm using Microsoft SQL Server 2012.
Thank you very much
Edit 2014/06/24
My goal is to generate an XML of the full path and split path.
Actually, here is my idea :
1 - Identify all the ID in a temporary table to do loop
--On déclare une table tempo declare @IdTable Table ( id int, src nvarchar(max))
--On injecte tous les id existant de la table insert into @IdTable (id, src) select id, src from albo
--on déclare l'id de début en commencant par le plus petit declare @id int = (select min(id) from ALBO)
--Tnat qu'il reste des ID on continue la boucle while @id is not null begin
print @id select @id = min(id) from @IdTable where ID > @id end --Fin de la boucle des ID
2 - Split each row and update column (Colx => The Clolumns have been created before) This code should be placed into my previous loop.
Declare @products varchar(max) = 'W:\2-Work\ALBO\13_WP Reporting\13_07_Monthly reports\13_07_01 Archives\2012\201211\Draft\ALBO-MR-201211\gp_scripts\v1\Top10_duree_final.txt' Declare @individual varchar(max) = null
WHILE LEN(@products) > 0 BEGIN IF PATINDEX('%\%',@products) > 0 BEGIN SET @individual = SUBSTRING(@products, 0, PATINDEX('%\%',@products)) select @individual --i have to make and update with the ID
SET @products = SUBSTRING(@products, LEN(@individual + '\') + 1,
LEN(@products))
END
ELSE
BEGIN
SET @individual = @products
SET @products = NULL
print @individual
END
END
回答1:
As others have said, this probably isn't the best way to do things, if you explain what you'll be doing with the results it might help us provide a better option
[Also, for some reason the colours of the code below are showing up odd, so copy and paste it into your Sql server to see it better]
drop table #Path
create table #Path (item bigint,location varchar(1000))
insert into #Path
select 16 ,'W:\2-Work\ALBO\00_Proposal\ALxO_Amendement #1_20091022_signed.pdf' union
select 17 ,'W:\2-Work\ALBO\00_Proposal\Level1\ALBO_Amendment #1_20110418.docx' union
select 18 ,'W:\2-Work\ALBO\00_Proposal\A\BR\T\X_#1_20110418_final.docx' union
select 19 ,'W:\2-Work\ALBO\MyOptionl\AO_Amendment_2 August 2013.docx'
select * from #Path;
with Path_Expanded(item,subitem,location, start, ending, split)
as(
select item
, 1 --subitem begins at 1
, location -- full location path
, 0 --start searching the file from the 0 position
, charindex('\',location) -- find the 1st '\' charactor
, substring(location,0,charindex('\',location)) --return the string from the start position, 0, to the 1st '\' charactor
from #Path
union all
select item
, subitem+1 --add 1 to subitem
, location -- full location path
, ending+1 -- start searching the file from the position after the last '\' charactor
, charindex('\',location,ending+1)-- find the 1st '\' charactor that occurs after the last '\' charactor found
, case when charindex('\',location,ending+1) = 0 then substring(location,ending+1,1000) --if you cant find anymore '\', return everything else after the last '\'
else substring(location,ending+1, case when charindex('\',location,ending+1)-(ending+1) <= 0 then 0
else charindex('\',location,ending+1)-(ending+1) end )--returns the string between the last '\' charactor and the next '\' charactor
end
from Path_Expanded
where ending > 0 --stop once you can't find anymore '\' charactors
)
--pivots the results
select item
, max(case when subitem = 1 then split else '' end) as col1
, max(case when subitem = 2 then split else '' end) as col2
, max(case when subitem = 3 then split else '' end) as col3
, max(case when subitem = 4 then split else '' end) as col4
, max(case when subitem = 5 then split else '' end) as col5
, max(case when subitem = 6 then split else '' end) as col6
, max(case when subitem = 7 then split else '' end) as col7
, max(case when subitem = 8 then split else '' end) as col8
, max(case when subitem = 9 then split else '' end) as col9
, max(case when subitem = 10 then split else '' end) as col10
from Path_Expanded
group by item
you might prefer to have each folder on its own row, if so replace the pivot part above with the below query instead
select item
, subitem
, location
, split from Path_Expanded where item = 16
回答2:
The following query will get what you are looking for; as others have noted, it's not a particularly good design. For example, what happens when you're looking for the file name and it's in a different column each time?
Regardless, this will do what you asked for (and maybe even what you want):
-- Test Data
CREATE TABLE #FilePath (FileNumber INT IDENTITY(1,1), FilePath VARCHAR(1000))
INSERT INTO #FilePath (FilePath)
SELECT 'W:\2-Work\ALBO\00_Proposal\ALxO_Amendement #1_20091022_signed.pdf' UNION
SELECT 'W:\2-Work\ALBO\00_Proposal\Level1\ALBO_Amendment #1_20110418.docx' UNION
SELECT 'W:\2-Work\ALBO\00_Proposal\A\BR\T\X_#1_20110418_final.docx' UNION
SELECT 'W:\2-Work\ALBO\MyOptionl\AO_Amendment_2 August 2013.docx'
GO
-- Numbers CTE
WITH Numbers AS
(
SELECT n = 1
UNION ALL
SELECT n + 1
FROM Numbers
WHERE n+1 <= 1000 -- set this to the maximum length of your file path
)
SELECT
FilePath,
[1] AS Col1,
[2] AS Col2,
[3] AS Col3,
[4] AS Col4,
[5] AS Col5,
[6] AS Col6,
[7] AS Col7,
[8] AS Col8,
[9] AS Col9,
[10] AS Col10
FROM
(
SELECT
FilePath,
ROW_NUMBER() OVER (PARTITION BY FilePath ORDER BY n) RowNum,
CAST(LTRIM(RTRIM(NULLIF(SUBSTRING('\' + FilePath + '\' , n , CHARINDEX('\' , '\' + FilePath + '\' , n) - n) , ''))) AS VARCHAR(1000)) FolderName
FROM Numbers, #FilePath
WHERE
n <= Len('\' + FilePath + '\') AND SubString('\' + FilePath + '\' , n - 1, 1) = '\' AND
CharIndex('\' , '\' + FilePath+ '\' , n) - n > 0
)P
PIVOT
(MAX(FolderName) FOR RowNum IN
([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])
) UP
OPTION (MAXRECURSION 1000)-- set this to the maximum length of your file path
-- Clean up
DROP TABLE #FilePath
回答3:
One way (de-dupes):
;with T(ordinal, path, starts, pos) as (
select 1, path, 1, charindex('\', path) from #tbl
union all
select ordinal + 1, path, pos + 1, charindex('\', path, pos + 1)
from t where pos > 0
)
select [1],[2],[3],[4],[5],[6],[7],[8],[9],[10] from (
select
ordinal, path, substring(path, starts, case when pos > 0 then pos - starts else len(path) end) token
from T
) T2
pivot (max(token) for ordinal in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) T3
来源:https://stackoverflow.com/questions/24364967/split-string-in-column-and-add-value-in-column