表名:表1一列拆分爲更多列的SQL Server 2008?
id name
1 1-aaa-14 milan road
2 23-abcde-lsd road
3 2-mnbvcx-welcoome street
我想是這樣的結果:
Id name name1 name2
1 1 aaa 14 milan road
2 23 abcde lsd road
3 2 mnbvcx welcoome street
表名:表1一列拆分爲更多列的SQL Server 2008?
id name
1 1-aaa-14 milan road
2 23-abcde-lsd road
3 2-mnbvcx-welcoome street
我想是這樣的結果:
Id name name1 name2
1 1 aaa 14 milan road
2 23 abcde lsd road
3 2 mnbvcx welcoome street
這個功能應該給你你需要什麼。
--Drop Function Dbo.Part
Create Function Dbo.Part
(@Value Varchar(8000)
,@Part Int
,@Sep Char(1)='-'
)Returns Varchar(8000)
As Begin
Declare @Start Int
Declare @Finish Int
Set @Start=1
Set @Finish=CharIndex(@Sep,@Value,@Start)
While (@Part>1 And @Finish>0)Begin
Set @[email protected]+1
Set @Finish=CharIndex(@Sep,@Value,@Start)
Set @[email protected]
End
If @Part>1 Set @Start=Len(@Value)+1 -- Not found
If @Finish=0 Set @Finish=Len(@Value)+1 -- Last token on line
Return SubString(@Value,@Start,@[email protected])
End
用法:
Select ID
,Dbo.Part(Name,1,Default)As Name
,Dbo.Part(Name,2,Default)As Name1
,Dbo.Part(Name,3,Default)As Name2
From Dbo.Table1
這是相當計算密集型的,因此,如果表1是非常長的,你應該寫結果到另一個表,你可以從時間刷新時間(也許一次一天,晚上)。
更好的是,您可以創建一個觸發器,每當對Table1進行更改時都會自動更新Table2。假設列ID是主鍵:
Create Table Dbo.Table2(
ID Int Constraint PK_Table2 Primary Key,
Name Varchar(8000),
Name1 Varchar(8000),
Name2 Varchar(8000))
Create Trigger Trigger_Table1 on Dbo.Table1 After Insert,Update,Delete
As Begin
If (Select Count(*)From Deleted)>0
Delete From Dbo.Table2 Where ID=(Select ID From Deleted)
If (Select Count(*)From Inserted)>0
Insert Dbo.Table2(ID, Name, Name1, Name2)
Select ID
,Dbo.Part(Name,1,Default)
,Dbo.Part(Name,2,Default)
,Dbo.Part(Name,3,Default)
From Inserted
End
現在,做你的數據操作(插入,更新,刪除)上表1,但是做你的上表2 Select語句來代替。
如果你總是將有2個破折號,您可以通過使用PARSENAME
--testing table
CREATE TABLE #test(id INT, NAME VARCHAR(1000))
INSERT #test VALUES(1, '1-aaa-14 milan road')
INSERT #test VALUES(2, '23-abcde-lsd road')
INSERT #test VALUES(3, '2-mnbvcx-welcoome street')
SELECT id,PARSENAME(name,3) AS name,
PARSENAME(name,2) AS name1,
PARSENAME(name,1)AS name2
FROM (
SELECT id,REPLACE(NAME,'-','.') NAME
FROM #test)x
執行以下操作如果名稱列中有點,則必須先替換它們,然後將它們替換回最後的點
例如,通過使用一個波浪線來替代點
INSERT #test VALUES(3, '5-mnbvcx-welcoome street.')
SELECT id,REPLACE(PARSENAME(name,3),'~','.') AS name,
REPLACE(PARSENAME(name,2),'~','.') AS name1,
REPLACE(PARSENAME(name,1),'~','.') AS name2
FROM (
SELECT id,REPLACE(REPLACE(NAME,'.','~'),'-','.') NAME
FROM #test)x
還算不錯,但如果你總是有3個或更少的破折號它只能。哦,如果你沒有任何時期(正如你指出的那樣,你可以更換時期,然後恢復它們)。如果你沒有[方括號]。而且...我不確定ParseName如何處理以空格開頭或結尾的名稱部分,是嗎?一般來說,ParseName函數不是爲了這個目的;它專門用於數據庫對象名稱。 – 2011-05-12 18:04:21
這正是我所說的 – SQLMenace 2011-05-12 18:07:51
在我以前的評論中,只要我輸入第一個轉折點,我就錯誤地按下了「添加評論」。我立刻編輯完成了我的想法。我認爲@SQLMenace回覆了我評論的第一個版本,所以如果沒有意義,那是我的錯。 – 2011-05-12 18:10:59
以下解決方案使用recursiveCTE分割字符串,而PIVOT用於在各自的列中顯示零件。
WITH Table1 (id, name) AS (
SELECT 1, '1-aaa-14 milan road' UNION ALL
SELECT 2, '23-abcde-lsd road' UNION ALL
SELECT 3, '2-mnbvcx-welcoome street'
),
cutpositions AS (
SELECT
id, name,
rownum = 1,
startpos = 1,
nextdash = CHARINDEX('-', name + '-')
FROM Table1
UNION ALL
SELECT
id, name,
rownum + 1,
nextdash + 1,
CHARINDEX('-', name + '-', nextdash + 1)
FROM cutpositions c
WHERE nextdash < LEN(name)
)
SELECT
id,
[1] AS name,
[2] AS name1,
[3] AS name2
/* add more columns here */
FROM (
SELECT
id, rownum,
part = SUBSTRING(name, startpos, nextdash - startpos)
FROM cutpositions
) s
PIVOT (MAX(part) FOR rownum IN ([1], [2], [3] /* extend the list here */)) x
在不額外修改這個查詢可以分割的名字由多達100份(這是默認的最大遞歸深度,這是可以改變的),但只能顯示不超過3他們。您可以輕鬆地將其擴展到您希望顯示的多個部分,只需按照評論中的說明操作即可。
select T.id,
substring(T.Name, 1, D1.Pos-1) as Name,
substring(T.Name, D1.Pos+1, D2.Pos-D1.Pos-1) as Name1,
substring(T.Name, D2.Pos+1, len(T.name)) as Name2
from Table1 as T
cross apply (select charindex('-', T.Name, 1)) as D1(Pos)
cross apply (select charindex('-', T.Name, D1.Pos+1)) as D2(Pos)
建議的解決方案
的
測試性能
設置:
create table Table1
(
id int identity primary key,
Name varchar(50)
)
go
insert into Table1
select '1-aaa-14 milan road' union all
select '23-abcde-lsd road' union all
select '2-mnbvcx-welcoome street'
go 10000
結果:
我知道應該可以用CROSS APPLY!我對這項技術還不甚瞭解。無論如何,我的解決方案可能更快。 :) – 2011-05-13 06:51:08
@Andriy--對性能進行了一些測試:) – 2011-05-13 09:31:05
在我的假設以及之前關於比較結果的報告中,我有點太倉促。我得到的實際數字與您的數據完全一致。對不起,我是如此誤導。並感謝您的測試和發佈結果! – 2011-05-13 13:00:50
這是一個很好的方法 – Ravia 2013-02-04 09:32:55