数字递增时如何获取空值

时间:2015-03-03 05:13:10

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

我有一段看起来像这样的代码

declare @t table (record int,string varchar(MAX))
insert into @t (record,string)values (1,'ABC')
insert into @t (record,string)values (2,'DEF/123')
insert into @t (record,string)values (3,'GHI/456/XYZ')

我得到一个查询,我可以这样结果

SELECT record,
   RIGHT(LEFT(T.string,Number-1),CHARINDEX('/',REVERSE(LEFT('/' + T.string,number-1))))
FROM
    master..spt_values,
    @t T
WHERE
    Type = 'P' AND Number BETWEEN 1 AND LEN(T.string)+1
    AND
    (SUBSTRING(T.string,Number,1) = '/' OR SUBSTRING(T.string,Number,1)  = '') 

获得输出

record  values
    1   ABC
    2   DEF
    2   123
    3   GHI
    3   456
    3   XYZ

我怎样才能获得像这样的输出

record  values
    1   ABC
    1   NULL
    1   NULL
    2   DEF
    2   123
    2   NULL
    3   GHI
    3   456
    3   XYZ

一些用户已经问过了。我在这里表现得很好,从那里我如何实现欲望输出

4 个答案:

答案 0 :(得分:0)

我们的想法是生成一行record交叉加入1,2,3,以生成record与另一列编号为1,2,3的组合,然后使用该组合加入你的分裂价值。您必须先为分割值添加ROW_NUMBER,才能将其与生成的组合一起加入。

;WITH CteThree(record, N) AS(
    SELECT
        t.record,
        x.N
    FROM (
        SELECT DISTINCT record FROM @t
    )t
    CROSS JOIN(
        SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
    )x(N)
),
CteSplitted AS(
    SELECT
        record,
        ROW_NUMBER() OVER(PARTITION BY record ORDER BY Number) AS N,
        RIGHT(LEFT(T.string,Number-1),CHARINDEX('/',REVERSE(LEFT('/' + T.string,number-1)))) AS str
    FROM master..spt_values v
    CROSS JOIN @t T
    WHERE
        Type = 'P'
        AND Number BETWEEN 1 AND LEN(T.string)+1
        AND (SUBSTRING(T.string,Number,1) = '/' OR SUBSTRING(T.string,Number,1)  = '')
)
SELECT
    t.record,
    s.str
FROM CteThree t
LEFT JOIN CteSplitted s
    ON s.record = t.record
    AND s.N = t.N

答案 1 :(得分:0)

怎么样:

declare @t table (record int,string varchar(MAX));
declare @s char(1) = '/';

WITH counter as (
    SELECT MAX(LEN(string)-LEN(REPLACE(string, @s, ''))) lines
) ,
splitter as (
    SELECT record, string
         , line  = 1
         , pos   = h.pos
         , value = CASE WHEN h.pos>0 THEN SUBSTRING(string,1,h.pos) ELSE string END
    FROM @t
    CROSS APPLY (SELECT CHARINDEX(@s, string) pos ) h
    UNION ALL     
    SELECT record, string
         , line  = s.line + 1
         , pos   = CASE WHEN s.pos = 0 THEN 0 ELSE h.pos END
         , value = CASE WHEN s.pos = 0 THEN null
                        WHEN h.pos > 0 THEN SUBSTRING(string,s.pos+1,h.pos-s.pos-1) 
                        ELSE SUBSTRING(string,s.pos+1,99)
                   END
    FROM splitter s
    CROSS APPLY (SELECT CHARINDEX(@s, string, s.pos+1) pos ) h
    WHERE s.line<=(SELECT lines FROM counter)
)
SELECT * 
FROM splitter 
ORDER BY record,line    

答案 2 :(得分:0)

试试这个

DECLARE @t TABLE
    (
      record INT ,
      string VARCHAR(MAX)
    )
INSERT  INTO @t
        ( record, string )
VALUES  ( 1, 'ABC' ),
        ( 2, 'DEF/123' ),
        ( 3, 'GHI/456/XYZ' );
WITH    cte
          AS ( SELECT   Number = 1
               UNION ALL
               SELECT   Number + 1
               FROM     cte
               WHERE    Number <= 100
             ),
        NotNull
          AS ( SELECT   record ,
                        RIGHT(LEFT(T.string, Number - 1),
                              CHARINDEX('/',
                                        REVERSE(LEFT('/' + T.string,
                                                     number - 1)))) string ,
                        ROW_NUMBER() OVER ( PARTITION BY T.record ORDER BY T.record ) AS RN
               FROM     cte
                        JOIN @t T ON Number <= ( LEN(T.string) + 1 )
                                     AND SUBSTRING(T.string + '/', Number, 1) = '/'
             )
    SELECT  template.record ,
            NotNull.string
    FROM    ( SELECT    *
              FROM      ( SELECT  DISTINCT
                                    RN
                          FROM      NotNull
                        ) AS A
                        CROSS JOIN ( SELECT Record
                                     FROM   NotNull
                                   ) AS B
            ) AS template
            LEFT JOIN NotNull ON template.RN = NotNull.RN
                                 AND template.Record = NotNull.Record

答案 3 :(得分:0)

试试这个

 declare @t table (record int,string varchar(MAX))
    insert into @t (record,string)values (1,'ABC')
    insert into @t (record,string)values (2,'DEF/123')
    insert into @t (record,string)values (3,'GHI/456/XYZ')
    declare @mx int
    select @mx= len(string)-len(replace(string,'/','')) from @t
    select record,t.c.value('.','varchar(max)') as col2 from 
    (select record,x=cast('<t>'+replace(left(string+'////////////////////',(len(string)+(@mx-(len(string)-len(replace(string,'/','')))))),'/','</t><t>') +'</t>' as xml)  from @t) 
    a cross apply x.nodes('/t') t(c)