将一列/一列分成两列或多列

时间:2019-07-22 08:47:48

标签: sql-server etl

第一个帖子在这里!我正在尝试更新雇主的数据仓库中的存储过程,该存储过程将两个表链接到其ID上。该存储过程基于表A中的2列。它是主键,并且一列包含表B中的主键及其域。请注意,由于B的ID在其中,因此它实际上只需要表A。旧代码使用了一些PATINDEX / SUBSTRING代码,这些代码假设两件事:

  • FK总是 7个字符长
  • 域字符串看起来像这样的“ @ xx-yyyy”,其中xx必须是两个字符,而yyyy是四个字符。

但是问题是

  • 我们最近的7位FK数量已不多了,现在正在寻找7位或8位数字
  • 实现了更长的域字符串(xx可能在2或15个字符之间)
  • 有时没有域字符串。只是一些FK,以相同的方式定界。
  • 该代码的文献记录不充分,并且包含一些ID异常(不是问题,只是令人讨厌)

一些信息:

  • 数据仓库遵循Data Vault方法,此过程存储在SQL Server上,并由SSIS触发。在此过程之后,将对HUB和Satellite进行更新,简而言之:我不仅可以创建新的存储过程,还可以尝试将我的代码集成到旧的存储过程中。
  • 服务器在SQL Server 2012上运行,因此我无法使用string_split
  • 这个平台即将消失,所以我今年只需要“保持运行”即可。
  • ID和域总是 用一个空格分隔
  • 如果一条记录没有外键,它将总是具有空字符串
  • 当一条记录具有多个(外部)ID时,即使单个FK旁边没有域字符串,它也将始终使用相同的定界符。分隔符如下所示:

    "12345678 @xx-xxxx[CR][CR][CR][LF]12345679 @yy-xxxx"
    

我设法创建了一些可以分配行号的代码,并且可以灵活地识别FK的数量。

这是旧代码的一部分:

DECLARE 
    @MAXCNT INT = (SELECT MAX(ROW) FROM #Worktable),
    @C_ID INT,
    @R_ID INT,
    @SOURCE CHAR(5),
    @STRING VARCHAR(20),
    @VALUE CHAR(20),
    @LEN INT,
    @STARTSTRINGLEN INT =0,
    @MAXSTRINGLEN INT,

    @CNT INT = 1

WHILE @CNT <= @MAXCNT
BEGIN

SELECT @LEN=LEN(REQUESTS),@STRING =REQUESTS, @C_ID =C_ID  FROM #Worktable WHERE ROW = @CNT

--1 REQUEST RELATED TO ONE CHANGE
IF @LEN < 17
    BEGIN

    INSERT INTO #ChangeRequest
    SELECT @C_ID,SUBSTRING(@STRING,0,CASE WHEN PATINDEX('%-xxxx%',@STRING) = 0  THEN @LEN+1 ELSE PATINDEX('%-xxxx%',@STRING)-4 END)
    --SELECT @STRING AS STRING, @LEN AS LENGTH
    END
ELSE 
-- MULTIPLE REQUESTS RELATED TO ONE CHANGE
    SET @STARTSTRINGLEN = 0
    WHILE @STARTSTRINGLEN<@LEN
    BEGIN
    SET @MAXSTRINGLEN = (SELECT PATINDEX('%-xxxx%',SUBSTRING(@STRING,@STARTSTRINGLEN,@STARTSTRINGLEN+17)))+7

    INSERT INTO #ChangeRequest
    --remove CRLF
    SELECT @C_ID,
    REPLACE(REPLACE( 
        substring(@string,@STARTSTRINGLEN+1,@MAXSTRINGLEN )
    , CHAR(13), ''), CHAR(10), '')
    SET @STARTSTRINGLEN=@STARTSTRINGLEN+@MAXSTRINGLEN

    IF @MAXSTRINGLEN = 0 BEGIN SET @STARTSTRINGLEN = @len END

    END
    SET @CNT = @CNT + 1;
END;

由于此循环假定长度固定,因此我需要使其更加灵活。我的代码:

(CASE WHEN LEN([Requests]) = 0
            THEN 0
            ELSE (LEN(REPLACE(REPLACE(Requests,CHAR(10),'|'),CHAR(13),''))-LEN(REPLACE(REPLACE(Requests,CHAR(10),''),CHAR(13),'')))+1
         END)

这始终显示FK的准确数量,从而显示要创建的行数。现在,我需要创建一个循环,以物理方式创建这些行,并将FK和域分为两列。

来源表:

+---------+----------------------------------------------------------------------------+
| Some ID |                                 Other ID's                                 |
+---------+----------------------------------------------------------------------------+
|       1 | 21                                                                         |
|       2 | 31 @xxx-xxx                                                                |
|       3 | 41 @xxx-xxx[CR][CR][CR][LF]42 @yyy-xxx[CR][CR][CR][LF]43 @zzz-xxx          |
|       4 | 51[CR][CR][CR][LF]52[CR][CR][CR][LF]53 @xxx-xxx[CR][CR][CR][LF]54 @yyy-xxx |
|       5 | <empty string>                                                             |
+---------+----------------------------------------------------------------------------+

目标表:

+-----+----------------+----------------+
| SID |      OID       |     Domain     |
+-----+----------------+----------------+
|   1 | 21             | <empty string> |
|   2 | 31             | xxx-xxx        |
|   3 | 41             | xxx-xxx        |
|   3 | 42             | yyy-xxx        |
|   3 | 43             | zzz-xxx        |
|   4 | 51             | <empty string> |
|   4 | 52             | <empty string> |
|   4 | 53             | xxx-xxx        |
|   4 | 54             | yyy-xxx        |
|   5 | <empty string> | <empty string> |
+-----+----------------+----------------+

当前已创建所有行,但每个SID的第一行之后的每一行都是空的。

0 个答案:

没有答案
相关问题