一列拆分为更多列sql server 2008?

时间:2011-05-12 16:47:08

标签: tsql sql-server-2008

表名:表1

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

4 个答案:

答案 0 :(得分:3)

这个功能应该能满足你的需要。

--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 @Start=@Finish+1
    Set @Finish=CharIndex(@Sep,@Value,@Start)
    Set @Part=@Part-1
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,@Finish-@Start)
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

这是计算密集型的,所以如果Table1很长,你应该把结果写到另一个表,你可以不时刷新(也许每天一次,晚上)。

更好的是,您可以创建一个触发器,只要对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

现在,在Table1上进行数据操作(插入,更新,删除),但在Table2上执行Select语句。

答案 1 :(得分:1)

以下解决方案使用recursive CTE分割字符串,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个。您可以轻松地将其扩展到您想要显示的许多部分,只需按照注释中的说明进行操作即可。

答案 2 :(得分:1)

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

结果:

enter image description here

答案 3 :(得分:0)

如果您总是有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