如何根据SQL Server中的条件将特定数据从一列移动到另一列

时间:2017-07-11 02:40:39

标签: sql-server sql-server-2008

我的源表如下所示:

   Source table:
    ID      Col
    ----   --------------
     1     TAMATO / INNPU# HH55555     
     2     PATATO/9-1 666 000 0000         
     3     CARLI 1111110000/0002222000   
     4     BRINZAL          000-8888(CELL)
     5     LADY  INDAP444444444          
     6     PUMKIN   INNDP#123456789       
     7     HELLO/CELL#9-1-000-000-9900

我想按记录阅读记录,并希望根据以下条件将字段移动到另一个表:

 1. If there is a(or more) space or any special chars(e.g. /) before the 
 number.Then move the number part(starting from number till end of the 
 string) to the new table/column.

2.For any String(record) contain "CELL" or "AP" or "PU" or "ND" or "DP": 
then, Starting from the number, move 6 chars backward and within these 6 
chars, If any String(record) contain "CELL" or "AP" or "PU" or "ND" or 
"DP" - move these records (staring from "CELL" or "AP" or "PU" or "ND" or 
"DP" till end of the string) to another table/column.

所以我的决赛桌看起来如下所示。

结果表:

 ID      Col
----   --------------
 1     PU# HH55555     
 2     9-1 666 000 0000         
 3     1111110000/0002222000   
 4     000-8888(CELL)
 5     AP444444444          
 6     DD#123456789       
 7     CELL#9-1-000-000-9900

我写了以下查询;但是,它看起来有一些问题。

DECLARE @TableName VARCHAR(100)
DECLARE @find CURSOR
 SET @FIND = CURSOR FOR SELECT col FROM Source_Table WHERE col like '%[0-
 9]%';
 OPEN @find;

  FETCH NEXT FROM @find INTO @TableName;

 DECLARE @Data VARCHAR(max)

 WHILE @@FETCH_STATUS = 0
 BEGIN


   DECLARE @ParsedData VARCHAR(5)
  DECLARE @CompVal1 VARCHAR(5) = 'CELL#'
  SET @Data =  (SELECT col FROM Source_Table WHERE col = @TableName)
     SET @ParsedData = (SELECT right(left(@Data, PATINDEX('%[0-9]%', 
     @Data  ) - 1),6))

    IF (@ParsedData = @CompVal1)
    SELECT @ParsedData
   SELECT @Data, SUBSTRING(@Data, PATINDEX('%[0-9]%', @Data ),
   (LEN(@Data)-1))
   FETCH NEXT FROM @find INTO @TableName;
   END;
  CLOSE @find;
  DEALLOCATE @find;

更改了我的查询,如下所示,仍无法实现此目的:

declare @result table
(

  Col varchar(max) 
 );

 declare 
  @C as cursor,

 @Col as varchar(max),
 @Data VARCHAR(max);

  set @C = cursor fast_forward for
 SELECT Col FROM Source_Table WHERE Col like '%[0-9]%';
 open @C;
  fetch next from @C into @Col;
  select @Data = @Col

 while @@FETCH_STATUS = 0
begin

DECLARE @ParsedData VARCHAR(5)
--DECLARE @CompVal1 VARCHAR(5) = 'DPP# '
 --SET @ParsedData = (SELECT right(left(@Data, PATINDEX('%[0-9]%', @Data  
 -- ) - 1),5))
 --IF (@ParsedData = @CompVal1)
 --SELECT @ParsedData
 --SELECT @Data, SUBSTRING(@Data, PATINDEX('%[0-9]%', @Data ),
--(LEN(@Data)-1))

 SET @ParsedData = (SELECT left(@Data, PATINDEX('%[0-9]%', @Data  ) - 1))

 set @Col = @ParsedData

  insert into @result values(@Col)

  fetch next from @C into @Col;
  END;
 CLOSE @C;
 DEALLOCATE @C;

 Select * from @result

我如何根据我的结果表实现?

注意:我的表有100k这样的记录;没有光标的任何其他方式也会有所帮助。 感谢。

1 个答案:

答案 0 :(得分:1)

以下是涵盖条件1和条件2的“CELL”/“AP”部分的查询。

此查询使用COALESCE来获得最大的简洁性,可以用CASE表达式替换。

Number 1000000是一个任意大数字,用于确保SUBSTRING返回整个字符串。如果您的字符串可能大于1000000个字符,请将数字更改为更大的字符串。

DROP TABLE #TestData
CREATE TABLE #TestData( Col VARCHAR( 100 ))
INSERT INTO #TestData
VALUES
( 'PU# HH55555     ' ),
( '9-1 666 000 0000         '),
( '1111110000/0002222000   '),
( '000-8888(CELL)'),
( 'AP444444444          '),
( 'DD#123456789       '),
( 'CELL#9-1-000-000-9900'),
( 'AP    9-1-000-000-9900'),
( 'AP     9-1-000-000-9900'),
( 'asdf'),
('')

;WITH SomeNumbers AS(
SELECT 
    Col,
    COALESCE(
        -- Conditions execute in order of appearance i.e. try the first match if not matched, then then try the 2nd etc.
        CASE WHEN PATINDEX( '%[0-9]%', SUBSTRING( Col, NULLIF( PATINDEX( '%CELL%[0-9]%', Col ), 0 ), 7 )) > 0 THEN SUBSTRING( Col, PATINDEX( '%CELL%[0-9]%', Col ), 1000000 ) END,
        CASE WHEN PATINDEX( '%[0-9]%', SUBSTRING( Col, NULLIF( PATINDEX( '%AP%[0-9]%', Col ), 0 ), 7 )) > 0 THEN SUBSTRING( Col, PATINDEX( '%AP%[0-9]%', Col ), 1000000 ) END,
        /*
        Add your remaning conditions here using above conditions as an exmaple
        */
        SUBSTRING( Col , NULLIF( PATINDEX( '%[ /][0-9]%', Col ), 0 ) + 1, 1000000 )

    ) AS ParsedNumber
FROM #TestData
)
SELECT *
FROM SomeNumbers
WHERE NOT ParsedNumber IS NULL

条件如何运作:

COALESCE( ... - 返回第一个非NULL表达式。 COALESCE内的所有匹配条件都以这种方式写入,以便在字符串与给定条件不匹配时返回NULL,从而允许评估下一个条件。

SUBSTRING( Col , NULLIF( PATINDEX( '%[ /][0-9]%', Col ), 0 ) + 1, 1000000 )

  • PATINDEX( '%[ /][0-9]%', Col ) - 查找时的模式 第一个字符是任何字符是[和]之间的列表 紧接着是一个数字角色。如果找到模式,则返回 此模式开始的字符位置,如果模式不是,则为0 找到。
  • 如果NULLIF返回0,则
  • PATINDEX返回NULL 返回PATINDEX
  • 的字符位置
  • SUBSTRING - 返回 以PATINDEX OR返回的字符位置开头的字符串 如果未找到模式,则为NULL(因此NULLIF返回NULL)。

CASE WHEN PATINDEX( '%[0-9]%', SUBSTRING( Col, PATINDEX( '%CELL%[0-9]%', Col ), 7 )) > 0 THEN SUBSTRING( Col, PATINDEX( '%CELL%[0-9]%', Col ), 1000000 ) END

  1. PATINDEX( '%CELL%[0-9]%', Col ) - 检查是否有单词“CELL”后跟一个数字。其他字符可以出现在单词“CELL”和数字之间。返回单词“CELL”开始的字符位置。
  2. SUBSTRING( .., .., 7 ) - 从单词“CELL”开始抓取7个字符。这将是数字前最多可能的6个字符,第7个字符是数字。
  3. PATINDEX( '%[0-9]%', ... - 检查上面选择的7个字符中是否出现数字字符。