【问题标题】:SQL - Break down a field's data into separate rowsSQL - 将字段的数据分解为单独的行
【发布时间】:2013-07-08 09:18:29
【问题描述】:

例如,鉴于表 alpha 中的以下内容:

Field1 | Field2 | Field3
------------------------
Foo    | Bar    | ABCD

我如何将这些数据分解为:

Field1 | Field2 | Field3
------------------------
Foo    | Bar    | A
Foo    | Bar    | B
Foo    | Bar    | C
Foo    | Bar    | D

我确信有一个花哨的 join 技巧可以做到,但我想不通。速度优化不是优先事项 - 此查询仅用于一次性报告,所以我不介意它是否像糖蜜一样慢(让我有机会煮咖啡!)

【问题讨论】:

  • field 3 被任何东西分隔,例如逗号或只是每个字符或...?
  • Field3 的字符数是固定的吗?
  • 您需要将 column3 按每个字符拆分还是有别的?
  • 没有分隔符,不固定(但最多 6 个字符),按每个字符分隔

标签: sql sql-server


【解决方案1】:

您可以通过以下步骤轻松完成:

  1. Step1:创建一个可以将单词拆分为字符的sql表值函数。你可以通过运行以下脚本来做到这一点。

    CREATE FUNCTION [dbo].[SPLITWORD](
    @WORD VARCHAR(MAX) 
    ) RETURNS @words TABLE (item VARCHAR(8000))
    
     BEGIN
     declare @count int, @total int
     select @total = len(@WORD), @count = 0
    
     while @count <= @total
     begin
       insert into @words select substring(@WORD, @count, 1)
       select @count = @count + 1
     end
    
     RETURN
    END
    

2.Steps 运行以下查询,将返回您想要的结果。

    SELECT A.FIELD1 , A.Field2 , B.ITEM
    FROM alpha AS A
    CROSS APPLY
    (
    SELECT * FROM SPLITWORD(A.Field3) WHERE ITEM != ''
    ) AS B

【讨论】:

    【解决方案2】:

    您可以尝试以下操作:

    WITH CTE_LenF3 AS 
    (
      -- find the length of each field3
      SELECT Field1, Field2, LEN(Field3) as Len_F3
      FROM alpha
    )
    ,CTE_Numbers AS 
    (
     --generate numbers from 1 to LEN(Filed3) for each field1,field2 combination
      SELECT Field1, Field2, 1 AS Nmb FROM CTE_LenF3
      UNION ALL
      SELECT c.Field1, c.Field2, Nmb + 1 FROM CTE_Numbers n
      INNER JOIN CTE_LenF3 c ON c.Field1 = n.Field1 AND c.Field2 = n.Field2
      WHERE Nmb + 1 <= LEN_F3
    )
    --join generated numbers with actual table and use substring to get the characters
    SELECT a.Field1, a.Field2, SUBSTRING(a.Field3, n.Nmb, 1)
    FROM CTE_Numbers n
    INNER JOIN alpha a ON a.Field1 = n.Field1 AND a.Field2 = n.Field2
    ORDER BY a.Field1, a.Field2, n.Nmb
    

    SQLFiddle DEMO

    【讨论】:

      【解决方案3】:

      类似:

      declare @alpha table (Field1 varchar(20), Field2 varchar(20), Field3 varchar(6))
      insert into @alpha(Field1, Field2, Field3) values
      ('Foo','Bar','ABCD')
      
      ;With Numbers(n) as (
          select 1 union all select 2 union all select 3 union all
          select 4 union all select 5 union all select 6
      )
      select Field1,Field2,SUBSTRING(Field3,n,1)
      from
          @alpha
              inner join
          Numbers
              on
                  n <= LEN(Field3)
      

      (除非你已经有一个方便的Numbers 表,你没有在问题中提到,在这种情况下它更简单)

      结果:

      Field1               Field2               
      -------------------- -------------------- ----
      Foo                  Bar                  A
      Foo                  Bar                  B
      Foo                  Bar                  C
      Foo                  Bar                  D
      

      【讨论】:

        【解决方案4】:
        DECLARE @xml as xml,@str as varchar(100),@delimiter as varchar(10)
        SET @str='A,B,C,D,E'
        SET @delimiter =','
        SET @xml = cast(('<X>'+replace(@str,@delimiter ,'</X><X>')+'</X>') as xml)
        SELECT N.value('.', 'varchar(10)') as value FROM @xml.nodes('X') as T(N)
        

        替换你的分隔符

        【讨论】:

          【解决方案5】:

          以下查询以任何方式实现您的功能

          DECLARE @temp as table(newFiled3 varchar(1))
          DECLARE @str_Value varchar(50),@count int,@i int=1
          SET @str_Value=(SELECT Field3 FROM alpha)
          SET @count=LEN(@str_Value)
          WHILE(@i<=@count)
          BEGIN
              INSERT INTO  @temp VALUES (SUBSTRING ( @str_Value ,@i , 1 ))
          SET @i=@i+1
          END
          
          
          SELECT Field1,Field2,b.newFiled3 
          FROM tblStudent a inner join @temp b ON a.Field1='Foo'
          

          无论如何looping is not a good method,但我们仍然需要这样做,因为您的Filed3 ABCDdynamic

          【讨论】:

            猜你喜欢
            • 2022-06-10
            • 2019-05-17
            • 1970-01-01
            • 1970-01-01
            • 2015-12-04
            • 2012-03-10
            • 2023-03-12
            • 1970-01-01
            相关资源
            最近更新 更多