zoukankan      html  css  js  c++  java
  • 字符串分解

    --各种字符串分拆处理函数.sql 
    --


    --各种字符串分函数

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    Go

    --3.2.1 循环截取法
    CREATE FUNCTION f_splitSTR(
    @s   varchar(8000),   --待分拆的字符串
    @split varchar(10)     --数据分隔符
    )RETURNS @re TABLE(col varchar(100))
    AS
    BEGIN
        DECLARE @splitlen int
        SET @splitlen=LEN(@split+'a')-2
        WHILE CHARINDEX(@split,@s)>0
        BEGIN
            INSERT @re VALUES(LEFT(@s,CHARINDEX(@split,@s)-1))
            SET @s=STUFF(@s,1,CHARINDEX(@split,@s)+@splitlen,'')
        END
        INSERT @re VALUES(@s)
        RETURN
    END
    GO


    /*==============================================*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    GO

    --3.2.3.1 使用临时性分拆辅助表法
    CREATE FUNCTION f_splitSTR(
    @s   varchar(8000),  --待分拆的字符串
    @split varchar(10)     --数据分隔符
    )RETURNS @re TABLE(col varchar(100))
    AS
    BEGIN
        --创建分拆处理的辅助表(用户定义函数中只能操作表变量)
        DECLARE @t TABLE(ID int IDENTITY,b bit)
        INSERT @t(b) SELECT TOP 8000 0 FROM syscolumns a,syscolumns b

        INSERT @re SELECT SUBSTRING(@s,ID,CHARINDEX(@split,@s+@split,ID)-ID)
        FROM @t
        WHERE ID<=LEN(@s+'a') 
            AND CHARINDEX(@split,@split+@s,ID)=ID
        RETURN
    END
    GO

    /*==============================================*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    GO

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tb_splitSTR]') and objectproperty(id,N'IsUserTable')=1)
    drop table [dbo].[tb_splitSTR]
    GO

    --3.2.3.2 使用永久性分拆辅助表法
    --字符串分拆辅助表
    SELECT TOP 8000 ID=IDENTITY(int,1,1) INTO dbo.tb_splitSTR
    FROM syscolumns a,syscolumns b
    GO

    --字符串分拆处理函数
    CREATE FUNCTION f_splitSTR(
    @s     varchar(8000),  --待分拆的字符串
    @split  varchar(10)     --数据分隔符
    )RETURNS TABLE
    AS
    RETURN(
        SELECT col=CAST(SUBSTRING(@s,ID,CHARINDEX(@split,@s+@split,ID)-ID) as varchar(100))
        FROM tb_splitSTR
        WHERE ID<=LEN(@s+'a') 
            AND CHARINDEX(@split,@split+@s,ID)=ID)
    GO


    /*==============================================*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    GO

    --3.2.5 将数据项按数字与非数字再次拆份
    CREATE FUNCTION f_splitSTR(
    @s   varchar(8000),    --待分拆的字符串
    @split varchar(10)     --数据分隔符
    )RETURNS @re TABLE(No varchar(100),Value varchar(20))
    AS
    BEGIN
        --创建分拆处理的辅助表(用户定义函数中只能操作表变量)
        DECLARE @t TABLE(ID int IDENTITY,b bit)
        INSERT @t(b) SELECT TOP 8000 0 FROM syscolumns a,syscolumns b

        INSERT @re 
        SELECT    No=REVERSE(STUFF(col,1,PATINDEX('%[^-^.^0-9]%',col+'a')-1,'')),
            Value=REVERSE(LEFT(col,PATINDEX('%[^-^.^0-9]%',col+'a')-1))
        FROM(
            SELECT col=REVERSE(SUBSTRING(@s,ID,CHARINDEX(@split,@s+@split,ID)-ID))
            FROM @t
            WHERE ID<=LEN(@s+'a') 
                AND CHARINDEX(@split,@split+@s,ID)=ID)a
        RETURN
    END
    GO


    /*==============================================*/

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_splitSTR]') and xtype in (N'FN', N'IF', N'TF'))
    drop function [dbo].[f_splitSTR]
    GO

    --3.2.6 分拆短信数据
    CREATE FUNCTION f_splitSTR(@s varchar(8000))
    RETURNS @re TABLE(split varchar(10),value varchar(100))
    AS
    BEGIN
        DECLARE @splits TABLE(split varchar(10),splitlen as LEN(split))
        INSERT @splits(split)
        SELECT 'AC' UNION ALL
        SELECT 'BC' UNION ALL
        SELECT 'CC' UNION ALL
        SELECT 'DC'    
        DECLARE @pos1 int,@pos2 int,@split varchar(10),@splitlen int
        SELECT TOP 1 
            @pos1=1,@split=split,@splitlen=splitlen
        FROM @splits
        WHERE @s LIKE split+'%'
        WHILE @pos1>0
        BEGIN
            SELECT TOP 1
                @pos2=CHARINDEX(split,@s,@splitlen+1)
            FROM @splits
            WHERE CHARINDEX(split,@s,@splitlen+1)>0
            ORDER BY CHARINDEX(split,@s,@splitlen+1)
            IF @@ROWCOUNT=0
            BEGIN
                INSERT @re VALUES(@split,STUFF(@s,1,@splitlen,''))
                RETURN
            END
            ELSE
            BEGIN
                INSERT @re VALUES(@split,SUBSTRING(@s,@splitlen+1,@pos2-@splitlen-1))
                SELECT TOP 1 
                    @pos1=1,@split=split,@splitlen=splitlen,@s=STUFF(@s,1,@pos2-1,'')
                FROM @splits
                WHERE STUFF(@s,1,@pos2-1,'') LIKE split+'%'
            END
        END
        RETURN
    END
    GO

    /*
    标题:分解字符串并查询相关数据
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开) 
    时间:2008-03-18
    地点:广东深圳
    说明:通过使用函数等方法分解字符串查询相关数据。

    问题:通过分解一个带某种符号分隔的字符串在数据库中查找相关数据。
    例如 @str = '1,2,3',查询下表得到记录1,4,5,6
    ID TypeID
    1  1,2,3,4,5,6,7,8,9,10,11,12
    2  2,3 
    3  3,7,8,9 
    4  2,6 
    5  4,5
    6  6,7 
    */
    -----------------------------
    create table tb (ID int , TypeID varchar(30)) 
    insert into tb values(1 , '1,2,3,4,5,6,7,8,9,10,11,12') 
    insert into tb values(2 , '2,3') 
    insert into tb values(3 , '3,7,8,9') 
    insert into tb values(4 , '2,6') 
    insert into tb values(5 , '4,5')
    insert into tb values(6 , '6,7')
    go
    -----------------------------
    --如果仅仅是一个,如@str = '1'.
    declare @str as varchar(30)
    set @str = '1'
    select * from tb where charindex(',' + @str + ',' , ',' + TypeID + ',') > 0
    select * from tb where ',' + TypeID + ',' like '%,' + @str + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    (所影响的行数为 1 行)
    */

    -----------------------------
    --如果包含两个,如@str = '1,2'.
    declare @str as varchar(30)
    set @str = '1,2'
    select * from tb where charindex(',' + left(@str , charindex(',' , @str) - 1) + ',' , ',' + typeid + ',') > 0 or 
      charindex(',' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',' , ',' + typeid + ',') > 0
    select * from tb where ',' + typeid + ',' like '%,' + left(@str , charindex(',' , @str) - 1) + ',%' or 
      ',' + typeid + ',' like '%,' + substring(@str , charindex(',' , @str) + 1 , len(@str)) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    4           2,6
    (所影响的行数为 3 行)
    */

    -------------------------------------------
    --如果包含三个或四个,用PARSENAME函数来处理.
    declare @str as varchar(30)
    set @str = '1,2,3,4'
    select * from tb where 
      charindex(',' + parsename(replace(@str , ',' , '.') , 4) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 3) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 2) + ',' , ',' + typeid + ',') > 0 or
      charindex(',' + parsename(replace(@str , ',' , '.') , 1) + ',' , ',' + typeid + ',') > 0 
    select * from tb where 
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 4) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 3) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 2) + ',%' or
      ',' + typeid + ',' like '%,' + parsename(replace(@str , ',' , '.') , 1) + ',%'
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */

    ---------------------------------------
    --如果超过四个,则只能使用函数或动态SQL来分解并查询数据。
    /*
    名称:fn_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 @str as varchar(30)
    set @str = '1,2,3,4,5'

    select distinct m.* from tb m,
    (select * from dbo.fn_split(@str,',')) n
    where charindex(',' + n.a + ',' , ',' + m.typeid + ',') > 0

    drop table tb
    drop function dbo.fn_split

    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */

    ------------------------------------------
    --使用动态SQL的语句。
    declare @str varchar(200)
    declare @sql as varchar(1000)
    set @str = '1,2,3,4,5'
    set @sql = 'select ''' + replace(@str , ',' , ''' as id union all select ''')
    set @sql = @sql + ''''
    set @sql = 'select distinct a.* from tb a , (' + @sql + ') b where charindex(' + ''','' + b.id + ' + ''',''' + ' , ' + ''','' + a.typeid + ' + ''',''' + ') > 0 '
    exec (@sql)
    /*
    ID          TypeID                         
    ----------- ------------------------------ 
    1           1,2,3,4,5,6,7,8,9,10,11,12
    2           2,3
    3           3,7,8,9
    4           2,6
    5           4,5
    (所影响的行数为 5 行)
    */

     ---分拆列值

    --原著:邹建 
    --改编:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)  2007-12-16  广东深圳

    --有表tb, 如下: 
    id          value 
    ----------- --------
    1          aa,bb 
    2          aaa,bbb,ccc 
    欲按id,分拆value列, 分拆后结果如下: 
    id          value 
    ----------- -------- 
    1          aa 
    1          bb 
    2          aaa 
    2          bbb 
    2          ccc

    1. 旧的解决方法(sql server 2000) 
    SELECT TOP 8000 id = IDENTITY(int, 1, 1) INTO # FROM syscolumns a, syscolumns b

    SELECT A.id, SUBSTRING(A.[values], B.id, CHARINDEX(',', A.[values] + ',', B.id) - B.id) 
    FROM tb A, # B 
    WHERE SUBSTRING(',' + A.[values], B.id, 1) = ','

    DROP TABLE #

    2. 新的解决方法(sql server 2005)

    create table tb(id int,value varchar(30)) 
    insert into tb values(1,'aa,bb') 
    insert into tb values(2,'aaa,bbb,ccc') 
    go 
    SELECT A.id, B.value 
    FROM( 
        SELECT id, [value] = CONVERT(xml,' <root> <v>' + REPLACE([value], ',', ' </v> <v>') + ' </v> </root>') FROM tb 
    )A 
    OUTER APPLY( 
        SELECT value = N.v.value('.', 'varchar(100)') FROM A.[value].nodes('/root/v') N(v) 
    )B

    DROP TABLE tb

    /* 
    id          value 
    ----------- ------------------------------ 
    1          aa 
    1          bb 
    2          aaa 
    2          bbb 
    2          ccc

    (5 行受影响) 
    */

  • 相关阅读:
    榨干PHP性能的使用细节
    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
    Oracle 表锁处理总结
    Windows安装NodeJS
    RedHed5.8 重装yum
    linux Redhat5.8 升级 openSLL 无法升级成功,解决办法
    idea安装详情
    Linux升级OpenSSH 和 OpenSSL 详细步骤
    Oracle dmp文件 exp导出,imp导入
    redis哨兵模式增加密码认证
  • 原文地址:https://www.cnblogs.com/accumulater/p/6158599.html
Copyright © 2011-2022 走看看