SQL - 将字段的数据分解为单独的行
Posted
技术标签:
【中文标题】SQL - 将字段的数据分解为单独的行【英文标题】:SQL - Break down a field's data into separate rows 【发布时间】: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 按每个字符拆分还是有别的?
SQL query to split column data into rows 的可能重复项
没有分隔符,不固定(但最多 6 个字符),按每个字符分隔
【参考方案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 ABCD
是dynamic
【讨论】:
以上是关于SQL - 将字段的数据分解为单独的行的主要内容,如果未能解决你的问题,请参考以下文章