2014-01-24 39 views
0

我在'result'字段的'dataset'表中有4行,并且按照&符号分隔(&)。我想根据字段名称将'result'字段分成多个字段。我如何在SSIS或SQL中执行此操作?字段名称变得更高。如果没有.net脚本,它会很好。如果你注意到,字段名称混乱。ms sql根据数据分割为&列名称

结果(字段名)

DEPTID = 1 & 姓名 =嚣& 姓氏 = KAL & 中间名 =琴

姓名 =拉吉& 姓氏 =普利& 中间名 =库马尔& DEPTID = 2

姓名 =帕& 姓氏 = GUD & 中间名 = kumarrao

DEPTID = 7 & 姓名 = sha & 姓氏=绞纱

输出

**deptid** **firstname** **lastname** **middlename** 

1    din    kal    kum 

2    raj    puli    kumar 

       pavan   gud    kumarrao 

7    sha    hank  
+1

Yeesh,你为什么首先在你的数据库中存储JSON字符串? –

回答

1

CROSS APPLY某种形式split string函数的表。使用这些结果创建一个动态SQL命令并执行。坚持这些结果到一个新的表和DROP旧的。像那样存储数据是not okay

随机SplitString:

IF NOT EXISTS (SELECT 1 
       FROM sys.objects 
       WHERE name = 'SplitString' 
        AND type = 'TF') 
BEGIN 
    --DROP FUNCTION dbo.SplitString; 
    EXEC('CREATE FUNCTION dbo.SplitString() RETURNS @t TABLE (x BIT) AS BEGIN RETURN; END'); 
END; 
GO 

ALTER FUNCTION dbo.SplitString 
(
    @String    VARCHAR(MAX), 
    @Delimiter   VARCHAR(16) 
) RETURNS @Values TABLE 
(
    SplitString   VARCHAR(MAX)   
) AS BEGIN 
    /* 
     dbo.SplitString 

     @Param: 
     String, the string to be split, 
     Delimiter, the delimiter to use. 

     @Returns: 
     Table, each tuple consisting of a tokenized value of the original string, 
      split by the provided delimiter. Empty expressions result in NULL values. 

     @Example: 
     SELECT * 
     FROM dbo.SplitString('This is a test', ' '); 

     SELECT * 
     FROM dbo.SplitString(NULL, ' ');  
    */ 
    DECLARE @i   INTEGER, 
      @Split  VARCHAR(MAX), 
      @RowCount INTEGER; 
     SET @RowCount = 0; 

     SET @i = -1;   
    WHILE (LEN(ISNULL(@String, '')) > 0) 
    BEGIN 
     SET @String = LTRIM(RTRIM(@String)); 

     SET @i = CHARINDEX(@Delimiter, @String); 
     IF (@i = 0) 
     BEGIN 
      INSERT INTO @Values (SplitString) 
      VALUES (LTRIM(RTRIM(@String))); 

      SET @String = ''; 
     END ELSE BEGIN 
      INSERT INTO @Values (SplitString) 
      VALUES (LTRIM(RTRIM(LEFT(@String, @i - LEN(@Delimiter))))); 

      SET @String = RIGHT(@String, LEN(@String) - @i); 
     END; 

     SET @RowCount = @RowCount + 1; 
    END; 

    IF (@RowCount = 0) 
    BEGIN 
     INSERT INTO @Values (SplitString) 
     VALUES (NULL); 
    END; 

    RETURN; 
END; 
GO 

测试用例:

IF NOT EXISTS (SELECT 1 
       FROM sys.objects 
       WHERE name = 'DropThisNotAtomicNonsense' 
        AND type = 'U') 
BEGIN 
    --DROP TABLE dbo.DropThisNotAtomicNonsense; 
    CREATE TABLE dbo.DropThisNotAtomicNonsense 
    (
     DropThisNotAtomicNonsense_PK TINYINT IDENTITY(1, 1) NOT NULL, 
              PRIMARY KEY (DropThisNotAtomicNonsense_PK), 
     Result   VARCHAR(MAX) 
    ); 

    INSERT INTO dbo.DropThisNotAtomicNonsense (Result) 
    VALUES ('deptid=1 & firstname=din & lastname=kal & middlename=kum'), 
      ('firstname=raj & lastname=puli & middlename=kumar & deptid=2'), 
      ('firstname=pavan & lastname=gud & middlename=kumarrao'), 
      ('deptid=7 & firstname=sha & lastname=hank'); 
END; 
GO 

问题解决:

SET NOCOUNT ON; 

DECLARE @Cols  VARCHAR(MAX), 
     @SQL  NVARCHAR(MAX); 

CREATE TABLE #t_KeyValue 
(
    OriginalEntity TINYINT, 
    FieldName  VARCHAR(MAX), 
    FieldValue  VARCHAR(MAX) 
); 

INSERT INTO #t_KeyValue (OriginalEntity, FieldName, FieldValue) 
SELECT OriginalEntity = ugh.DropThisNotAtomicNonsense_PK, 
     FieldName = LEFT(x.SplitString, CHARINDEX('=', x.SplitString) - 1), 
     FieldValue = RIGHT(x.SplitString, CHARINDEX('=', REVERSE(x.SplitString)) - 1) 
FROM dbo.DropThisNotAtomicNonsense ugh 
CROSS APPLY dbo.SplitString(ugh.Result, '&') x; 

CREATE TABLE #t_ColumnList 
(
    FieldName    VARCHAR(MAX), 
    Processed    TINYINT NOT NULL DEFAULT 0 
); 

INSERT INTO #t_ColumnList (FieldName) 
SELECT DISTINCT FieldName 
FROM #t_KeyValue; 

IF NOT EXISTS (SELECT 1 
       FROM sys.objects 
       WHERE name = 'NormalTable' 
        AND type = 'U') 
BEGIN 
    --DROP TABLE dbo.NormalTable; 
    CREATE TABLE dbo.NormalTable 
    (
     NormalTable_PK  TINYINT IDENTITY(1, 1) NOT NULL, 
           PRIMARY KEY (NormalTable_PK), 
     OriginalEntity  TINYINT 
    ) 

    WHILE EXISTS ( SELECT 1 
       FROM #t_ColumnList 
       WHERE Processed = 0) 
    BEGIN 
     SELECT @SQL = FieldName 
     FROM #t_ColumnList 
     WHERE Processed = 0; 

     UPDATE #t_ColumnList 
      SET Processed = 1 
     WHERE FieldName = @SQL; 

     SET @SQL = N' 
      ALTER TABLE dbo.NormalTable 
      ADD [' + REPLACE(@SQL, '''', '') + ']  VARCHAR(128);' 
     EXECUTE dbo.sp_executesql @command = @SQL; 
    END; 

    SELECT @Cols = ISNULL(@Cols, '') + '[' + FieldName + '], ' 
    FROM ( SELECT DISTINCT FieldName 
      FROM #t_KeyValue) l 
     SET @Cols = LEFT(@Cols, LEN(@Cols) - 1); 

    SET @SQL = N' 
     INSERT INTO dbo.NormalTable (OriginalEntity, ' + @Cols + ') 
     SELECT OriginalEntity, ' + @Cols + ' 
     FROM ( SELECT OriginalEntity, FieldName, FieldValue 
       FROM #t_KeyValue) s 
     PIVOT (MAX(FieldValue) FOR 
       FieldName IN (' + @Cols + ')) p;'; 
    RAISERROR (@SQL, 0, 1) WITH NOWAIT; 
    EXECUTE sp_executesql @command = @SQL; 
END; 
GO 

DROP TABLE #t_ColumnList; 
DROP TABLE #t_KeyValue; 
GO 

SELECT * 
FROM dbo.NormalTable; 
GO 

DROP TABLE dbo.DropThisNotAtomicNonsense; 
GO 

SET NOCOUNT OFF; 

无w,用你的漂亮的新表格,你可以使用ALTER ... COLUMN语句在这些列上切换到某些proper data types

0
with x as (
    select cast('<e col="' + replace(replace(result, '=', '">'), '&', '</e><e col="') + '</e>' as xml) as x 
     from dataset 
) 
select x.value('(/e[contains(@col, "deptid")])[1]', 'int') as deptid 
     ,x.value('(/e[contains(@col, "firstname")])[1]', 'nvarchar(255)') as firstname 
     ,x.value('(/e[contains(@col, "lastname")])[1]', 'nvarchar(255)') as lastname 
     ,x.value('(/e[contains(@col, "middlename")])[1]', 'nvarchar(255)') as middlename 
    from x 

应该提供你想要的。它使用中间XML对象和xml处理来实现结果。中间柱看起来像

<e col="deptid">1 </e><e col=" firstname">din </e><e col=" lastname">kal </e><e col=" middlename">kum</e> 

这个解决方案不是绝对傻瓜证明,但如果你是确保该格式是稳定的,并且不包含完全格式化奇条目,它应该工作。注意:我需要contains,因为SQL Server在XPath中似乎没有trim函数。如果数据中包含&=以用于其他目的而不是分隔字段名称与内容或分隔字段,即如果这些字符将包含在名称中。