【问题标题】:How to separate string based on condition?如何根据条件分隔字符串?
【发布时间】:2012-06-24 11:34:20
【问题描述】:
COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C 

我想将上面的字符串分隔为(Required Output)

col1       col2         col3     col4         col5    col6
COMMSTR1 NAC-NAM-P-C    FCPANAM1 NAC-NAM-P-C CHAZEL1 NAT-CBM-P-C 

我试过了。

SELECT Contact_assg_list_src,
Contact_Assg_List_Src = 
(
case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then left(Contact_Assg_List_Src,patindex('%[-]%',Contact_Assg_List_Src)-1)
ELSE Contact_Assg_List_Src
END),
(case WHEN Contact_Assg_List_Src IS NOT NULL and Contact_Assg_List_Src <> ''
then substring(Contact_Assg_List_Src,(Patindex('%[-]%',Contact_Assg_List_Src + ' ')-1),len(Contact_Assg_List_Src))
ELSE Contact_Assg_List_Src
END)
from dbo.FBMSRAW;

这给了我这样的输出

col1            col2 
COMMSTR1      NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C 

如何检查字符串是否有空格,然后根据该 分隔字符串以 得到所需的输出?

【问题讨论】:

  • TSQL 不是一个很好的字符串操作工具。您尝试在服务器上执行此操作是否有原因?
  • @Damien_The_Unbeliever 是的,因为我的工作是数据清理,所以除了这个我不能使用。
  • 列是固定的,我的意思是最多有多少个空格?你能假设它是 50 吗?
  • @ViswanathanIyeor 在您的预期结果中它有 6 个 cokumns。

标签: sql sql-server string sql-server-2008 tsql


【解决方案1】:

首先是一个分割文本的函数

create function [dbo].[f_split]
(
@param nvarchar(max), 
@delimiter char(1)
)
returns @t table (val nvarchar(max), seq int)
as
begin
set @param += @delimiter

;with a as
(
select cast(1 as bigint) f, charindex(@delimiter, @param) t, 1 seq
union all
select t + 1, charindex(@delimiter, @param, t + 1), seq + 1
from a
where charindex(@delimiter, @param, t + 1) > 0
)
insert @t
select substring(@param, f, t - f), seq from a
option (maxrecursion 0)
return
end
go

查询显示结果,假设最多有 6 个“单词”

declare @t table(txt nvarchar(500))

insert @t values ('COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C'),
('t1 t2 t3 t4 t5 t6')

select * from @t t
outer apply
(
select max(case when seq = 1 then val end) col1,
       max(case when seq = 2 then val end) col2,
       max(case when seq = 3 then val end) col3,
       max(case when seq = 4 then val end) col4,
       max(case when seq = 5 then val end) col5,
       max(case when seq = 6 then val end) col6
from dbo.f_split(t.txt, ' ')
) b

【讨论】:

  • 对不起,我删除了我的评论,您的代码运行良好,但是当我这样做时出现错误。 SELECT Contact_assg_list_src,dbo.f_split(Contact_Assg_List_Src,' ') from dbo.FBMSRAW 错误是 Cannot find either column "dbo" or the user-defined function or aggregate "dbo.f_split", or the name is ambiguous.
  • 我已经正确创建了函数,并且您的代码适用于您给定的示例。
【解决方案2】:

我已经写了下面的脚本来满足你的需求,但是你自己需要添加一些更多的逻辑,理解下面的脚本

创建一个虚拟表

CREATE TABLE TBL_TEMPSTRINGS(STRCOL VARCHAR(200),COL1 VARCHAR(50),
COL2 VARCHAR(50),COL3 VARCHAR(50))

插入表格中的值

INSERT INTO TBL_TEMPSTRINGS
SELECT Contact_assg_list_src From dbo.FBMSRAW

创建一个存储过程来更新你的虚拟表列,它将你的表名放在一个字符串中(为什么你可以用临时表名替换你的虚拟表)

CREATE PROC SP_SPLITWRODS(@TABLENAME VARCHAR(50),@COLCOUNT INT)
AS
BEGIN
    DECLARE @QRY VARCHAR(500)

    CREATE TABLE #TBL_TEMP(STRCOL VARCHAR(200))
    DECLARE @STRCOL VARCHAR(200)
    DECLARE @CURRINDEX INT
    DECLARE @TEMP INT
    DECLARE @COLINDEX INT 
    DECLARE @ROWID INT
    DECLARE @STRLEN INT
    DECLARE @TEMPVALUE VARCHAR(50)
    DECLARE @LASTWORD BIT 
    --CURSOR FOR YOUR TEMP TABLE
    DECLARE CUR_TEMP CURSOR LOCAL FOR SELECT STRCOL FROM #TBL_TEMP

    --CONSTRUCT QRY FOR FILLING YOUR TABLE
    SET @QRY='INSERT INTO #TBL_TEMP SELECT STRCOL FROM ' + @TABLENAME

    --FILL TABLE
    EXECUTE(@QRY)

    OPEN CUR_TEMP
    FETCH CUR_TEMP INTO @STRCOL
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @CURRINDEX=1
        SET @COLINDEX=1
        SET @LASTWORD=0
        --GET ' ' INDEX
        SET @TEMP=CHARINDEX(' ',@STRCOL,@CURRINDEX)
        WHILE @TEMP > 0
        BEGIN
            --YOU WILL GET THE VALUE SEPERATED BY SPACE
            SET @TEMPVALUE=SUBSTRING(@STRCOL,@CURRINDEX,@TEMP-@CURRINDEX)

            --ADD MORE LOGIC TO UPDATE YOUR COLUMNS (YOUR EXTRA COLUMNS)

            --CONTRUCT QRY TO UPDATE CORRESPONDING COL IN YOUR TABLE FOR THE ROW FETCHED
            --THIS UPDATES ALL ROWS, YOU NEED TO ADD ONE WHERE CONDITION TO UPDATE THE ROW
            SET @QRY='UPDATE ' + @TABLENAME + ' SET COL' + CAST(@COLINDEX AS VARCHAR) + '=''' + @TEMPVALUE + ''''

            EXEC(@QRY)

            --INCREMENT COL INDEX AFTER UPDATE OF LAST COLUMN
            SET @COLINDEX=@COLINDEX+1

            SET @CURRINDEX=@TEMP+1

            SET @TEMP=CHARINDEX(' ',@STRCOL,@CURRINDEX)

            IF @TEMP=0 AND @LASTWORD=0
            BEGIN
                SET @TEMP=LEN(@STRCOL)+1
                SET @LASTWORD=1
            END
        END

        FETCH CUR_TEMP INTO @STRCOL
    END

    CLOSE CUR_TEMP

    DEALLOCATE CUR_TEMP

END

执行你的过程

EXEC SP_SPLITWRODS 'TBL_TEMPSTRINGS',1

查看更新后的虚拟表

SELECT * FROM TBL_TEMPSTRINGS

目前它是更新由空格分隔的 3 列,您需要添加自己的逻辑来根据您收到的字符串更新列(以空格分隔)。

希望对你有帮助

【讨论】:

    【解决方案3】:

    如果您想在 SQL Server 中高效地执行此操作,我建议您使用 CLR 函数。

    但是如果你必须在 T-SQL 中做,这个函数会实现它(缓慢,并且以越来越低效的方式)

        create function SplitString
        (
            @splitchar char(1),
            @string varchar(500),
            @index int
        )
        returns varchar(500)
        as
        begin
    
        declare @split int, @start int, @loop bit, @i int, @ret varchar(500)
            select @start = 0, @i = 0
            select @split = charindex(@splitchar, @string, 0) 
    
            if @index>0
                select @loop = 1
            else
                select @loop = 0
    
            while @loop = 1
            begin
    
                select @start = @split+1
                select @split = charindex(@splitchar, @string, @start+1)
    
                if @split = 0
                begin
                    select @split = len(@string)+1
                end
    
                select @i = @i + 1
                if @i = @index
                begin
                    select @loop = 0
                end
    
            end
            if @split>@start
                select @ret = substring(@string, @start, @split-@start)
            else
                select @ret = null
    
            return @ret
        end
    
        select dbo.SplitString (' ', 'COMMSTR1-NAC-NAM-P-C FCPANAM1-NAC-NAM-P-C CHAZEL1-NAT-CBM-P-C', [0 based column number])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-22
      • 2019-09-19
      • 1970-01-01
      • 2020-04-18
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多