导航
  • 主页
  • 基础类
  • 应用实例
  • 新技术前沿

求助!通过字符串中的分界符,把一列分为多列!

bqb 2007-12-17 03:21:30

/*
sysbase 数据库
如何將现有的表1转换为表2 ,谢谢~
最好写个存储工程!

表1:

CNO MESSAGE
-----------------------------------------------------
001 2021 |AA |20070902|
002 2022 |CC |20070905|
003 2058 |BB |20070906|


表2:

CNO COLUMN1 COLUMN2 COLUMN3
-------------------------------------------------------------
001 2021 AA 20070902
002 2022 CC 20070905
003 2058 BB 20070906
...全文
382 点赞 收藏 41
写回复
41 条回复
切换为时间正序
请发表友善的回复…
发表回复
shirley_yue 2008-01-16
感谢LZ,感谢上面得高手!
回复
shirley_yue 2008-01-16
学习了
回复
wynlc 2008-01-16
--看一下,下边这个函数吧
CHARINDEX
返回字符串中指定表达式的起始位置。

语法
CHARINDEX ( expression1 , expression2 [ , start_location ] )

参数
expression1

一个表达式,其中包含要寻找的字符的次序。expression1 是一个短字符数据类型分类的表达式。

expression2

一个表达式,通常是一个用于搜索指定序列的列。expression2 属于字符串数据类型分类。

start_location

在 expression2 中搜索 expression1 时的起始字符位置。如果没有给定 start_location,而是一个负数或零,则将从 expression2 的起始位置开始搜索。
回复
yuelailiu 2008-01-16
路过,学习...
回复
中国风 2008-01-16

create table t(cno varchar(5),message varchar(50))
insert into t select '001','2021|AA|20070902|'
insert into t select '002','2022|CC|20070905|120|'
insert into t select '003','2058|BB|'

go
--分段截取函数
CREATE FUNCTION dbo.f_GetStr(
@s varchar(8000), --包含多个数据项的字符串
@pos int, --要获取的数据项的位置
@split varchar(10) --数据分隔符
)RETURNS varchar(100)
AS
BEGIN
IF @s IS NULL RETURN(NULL)
DECLARE @splitlen int
SELECT @splitlen=LEN(@split+'a')-2
WHILE @pos>1 AND CHARINDEX(@split,@s+@split)>0
SELECT @pos=@pos-1,
@s=STUFF(@s,1,CHARINDEX(@split,@s+@split)+@splitlen,'')
RETURN(ISNULL(LEFT(@s,CHARINDEX(@split,@s+@split)-1),''))
END
GO

select
cno ,
dbo.f_GetStr (message,1,'|') as col1,
dbo.f_GetStr (message,2,'|') as col2,
dbo.f_GetStr (message,3,'|') as col3,
dbo.f_GetStr (message,4,'|') as col4
from
t

/*
001 2021 AA 20070902
002 2022 CC 20070905 120
003 2058 BB

*/
回复
bqb 2008-01-16
分数不多没有照顾到得下次补上~
回复
bqb 2008-01-16
呵呵,在SQL Server 已经解决了!

如果在Sybase 就有点困难了!不管怎样要结帖了,谢谢大家!
回复
-狙击手- 2008-01-16
问题还没有解决吗
回复
bqb 2008-01-16
怎么不能再加分了?



提示信息
此贴已加过分!

回复
bqb 2008-01-16
没想到会有这么多的方法,我原先只是写个函数 “dbo.StrSite”来取得某字符在字符第N次出现的位置,再结合substirng,太麻烦了。

create Function StrSite(@Str varchar(2000) ,@Word varchar(20) ,@TimesNo int)
returns int
as
begin
declare @i int,@Times int
declare @WordLen int
set @Times=0
set @i=1
set @Wordlen=len(@Word)

while (@i< Len(@Str)+1 )
begin
if substring(@Str,@i,@Wordlen)=@word
set @times=@times+1
--print '第'+cast(@i as varchar(20)) +'是 : ' +cast(@Times as varchar(20))

if @times=@TimesNo
break
set @i=@i+1
end
return (@i)
end


谢谢大家,再加点分,不然这点怕大家不够分啊~

回复
dawugui 2008-01-15
--分解字符串的函数.

/*
功能:实现split功能的函数
*/

create function dbo.fn_split
(
@inputstr varchar(8000),
@seprator varchar(10)
)
returns @temp table (a varchar(200))
as

begin
declare @i int

set @inputstr = rtrim(ltrim(@inputstr))
set @i = charindex(@seprator, @inputstr)

while @i >= 1
begin
insert @temp values(left(@inputstr, @i - 1))

set @inputstr = substring(@inputstr, @i + 1, len(@inputstr) - @i)
set @i = charindex(@seprator, @inputstr)
end

if @inputstr <> '\'
insert @temp values(@inputstr)

return
end
go

--调用

declare @s varchar(1000)

set @s='1,2,3,4,5,6,7,8,55'

select * from dbo.fn_split(@s,',')

drop function dbo.fn_split





回复
dawugui 2008-01-15
如果分隔符很多,采用函数来分割,估计上面已经有人写了.
回复
bqb 2008-01-15
树上的鸟儿
谢谢了!
用你的方法在SQL Server 中真的很方便



就Sybase 这破数据库,什么都不支持,

不支持自定义函数: select dbo.sssss(cno) from tk
set 也不能用
declare @a table(id int )定义表变量 也不能用

非常垃圾!
回复
chuifengde 2008-01-08
create table tk(cno varchar(5),message varchar(50))
insert into tk select '001','2021|AA|20070902|'
insert into tk select '002','2022|CC|20070905|120|'
insert into tk select '003','2058|BB|'

go
create proc GetCol
as
set nocount on
declare @max int,@i int
declare @sql varchar(8000)

set @i=1
select @max=max(len(message)-len(replace(message,'|',''))) from tk

select cno,message+replicate('|',@max-len(message)+len(replace(message,'|',''))) message into tkx from tk

while @i<=@max
begin
select @sql=isnull(@sql+',','')+'col'+ltrim(@i)+' varchar(50)',@i=@i+1
end
set @sql='create table tkxx(cno varchar(5),'+@sql+')'
exec(@sql)

set @i=1
insert tkxx(cno) select cno from tkx

while @i<=@max
begin
set @sql='
declare @a table(cno varchar(5),head varchar(50));
insert @a select cno,left(message,charindex(''|'',message)-1) from tkx;
update tkx set message=stuff(message,1,charindex(''|'',message),'''');
update tkxx set col'+ltrim(@i)+'=head from @a a where tkxx.cno=a.cno;'
exec(@sql)
set @i=@i+1
end
select * from tkxx
drop table tkx,tkxx

go
exec getCol
--result
/*
cno col1 col2 col3 col4
----- ------------------------------ ------------------------------ ------------------------------ ------------------------------
001 2021 AA 20070902
002 2022 CC 20070905 120
003 2058 BB
*/
回复
bqb 2008-01-08
谢谢,你太有心了!
pt1314917
背着灵魂漫步

还有个问题就是,我每条记录中有40几个分界符,所以不用几条数据@sql就超8000字符长度了!

要用到邹大哥的 “化解字符串不能超过8000的方法及交叉表的处理 “





回复
pt1314917 2008-01-03

没用我的这个试一下吗?
用SQL格式发个最终版本:
create table tk(cno varchar(5),message varchar(50))
insert into tk select '001','2021|AA|20070902|'
insert into tk select '002','2022|CC|20070905|120|'
insert into tk select '003','2058|BB|'

--创建函数:

create function sssss(@cno varchar(10))
returns varchar(2000)
as
begin
declare @message varchar(2000)
declare @i int,@num int,@c int
set @i=1
select @message=message from tk where cno=@cno
select @num=max(len(replace(message,' ',''))-len(replace(replace(message,' ',''),'|',''))) from tk
set @c=len(replace(@message,' ',''))-len(replace(replace(@message,' ',''),'|',''))
set @message=@message+replicate(' |',@num-@c)
while(charindex('|',@message)>0)
begin
set @message=stuff(@message,charindex('|',@message),1,''' columns'+cast(@i as varchar)+',''')
set @i=@i+1
end
set @message=left(@message,len(@message)-2)
return ''''+@cno+''' cno,'''+@message
end
go

--创建存储过程
create proc wsp
as
declare @sql varchar(8000)
select @sql=isnull(@sql+' union select ','select ')+dbo.sssss(cno) from tk
exec(@sql)

--执行存储过程
exec wsp

回复
bqb 2008-01-03
加分!加分!
回复
bqb 2008-01-03
记录数有几十万条,而且字符串中的的分节符有几十个啊,好慢!
如何才能高效呢~


dawugui
潇洒老乌龟

dawugui
潇洒老乌龟
等 级:
发表于:2008-01-02 16:01:3213楼 得分:0
SQL code--SQL SERVER的写法如下:
create table tb(CNO varchar(10), MESSAGE varchar(30))
insert into tb values('001', '2021|AA|20070902|')
insert into tb values('002', '2022|CC|20070905|')
insert into tb values('003', '2058|BB|20070906|')
go

select cno ,
PARSENAME(replace(left(MESSAGE,len(message)-1),'|','.'),3) column1,
PARSENAME(replace(left(MESSAGE,len(message)-1),'|','.'),2) column2,
PARSENAME(replace(left(MESSAGE,len(message)-1),'|','.'),1) column3
from tb

drop table tb

/*
cno column1 column2 column3
---------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
001 2021 AA 20070902
002 2022 CC 20070905
003 2058 BB 20070906

(3 行受影响)
*/


有好多列,所以PARSENAME 恐怕不行!


回复
qiule 2008-01-03
高手多啊,学习
回复
bqb 2008-01-03
SQL 就是人多,高手也多!
回复
发动态
发帖子
MS-SQL Server
创建于2007-09-28

3.2w+

社区成员

MS-SQL Server相关内容讨论专区
申请成为版主
社区公告
暂无公告