表名:表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