SQL,按 1 列拆分并复制其他列
SQL, Split by 1 column and duplicate other columns
美好的一天!
也许你可以帮助我,或者告诉我我想做的事情是不可能的还是完全错误的...
我正在尝试创建一个 sqlfiddle,但目前该页面似乎已关闭。
(SQL Server 2008) 我有一个 table,假设它有 3 列,但设计它的人没有归一化,所以一列包含多个值,它是这样的:
IdCol Col1 Col2 Col3
1 a1 b1 a, b, c
2 a2 b2 d, e, f
如您所见,Col3 包含多个由“,”分隔的值
我想要实现的是创建一个类似于此的视图(不能修改 table 因为他们不允许我修改应用程序):
NewIdCol IdCol Col1 Col2 Col3
1 1 a1 b1 a
2 1 a1 b1 b
3 1 a1 b1 c
4 2 a2 b2 d
5 2 a2 b2 e
6 2 a2 b2 f
因此,最终结果将 Col3 值拆分为不同的行,并复制所有其他列的值。 (实际的 table 有大约 20 列,其中 2 列包含多个值,所以我需要为两列都这样做)
起初我认为这很容易...但是后来我遇到了如何拆分该字符串的障碍...首先我想到了使用拆分功能,但后来我不知道如何加入它与其余列一起返回...
提前致谢。
您需要一个将逗号分隔的字符串拆分成单独行的函数。然后你像这样调用函数:
SELECT
NewIdCol = ROW_NUMBER() OVER(ORDER BY t.IdCol, x.ItemNumber),
t.IdCol,
t.Col1,
t.Col2,
x.Item
FROM Test t
CROSS APPLY [dbo].[DelimitedSplit8K](t.Col3, ',') x
这是 Jeff Moden 的 DelimitedSplit8K 函数。
CREATE FUNCTION [dbo].[DelimitedSplit8K](
@pString NVARCHAR(4000), @pDelimiter NCHAR(1)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS (SELECT 1 FROM E1 a, E1 b)
,E4(N) AS (SELECT 1 FROM E2 a, E2 b)
,cteTally(N) AS(
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
,cteStart(N1) AS(
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(
SELECT
s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;
美好的一天!
也许你可以帮助我,或者告诉我我想做的事情是不可能的还是完全错误的...
我正在尝试创建一个 sqlfiddle,但目前该页面似乎已关闭。
(SQL Server 2008) 我有一个 table,假设它有 3 列,但设计它的人没有归一化,所以一列包含多个值,它是这样的:
IdCol Col1 Col2 Col3
1 a1 b1 a, b, c
2 a2 b2 d, e, f
如您所见,Col3 包含多个由“,”分隔的值
我想要实现的是创建一个类似于此的视图(不能修改 table 因为他们不允许我修改应用程序):
NewIdCol IdCol Col1 Col2 Col3
1 1 a1 b1 a
2 1 a1 b1 b
3 1 a1 b1 c
4 2 a2 b2 d
5 2 a2 b2 e
6 2 a2 b2 f
因此,最终结果将 Col3 值拆分为不同的行,并复制所有其他列的值。 (实际的 table 有大约 20 列,其中 2 列包含多个值,所以我需要为两列都这样做)
起初我认为这很容易...但是后来我遇到了如何拆分该字符串的障碍...首先我想到了使用拆分功能,但后来我不知道如何加入它与其余列一起返回...
提前致谢。
您需要一个将逗号分隔的字符串拆分成单独行的函数。然后你像这样调用函数:
SELECT
NewIdCol = ROW_NUMBER() OVER(ORDER BY t.IdCol, x.ItemNumber),
t.IdCol,
t.Col1,
t.Col2,
x.Item
FROM Test t
CROSS APPLY [dbo].[DelimitedSplit8K](t.Col3, ',') x
这是 Jeff Moden 的 DelimitedSplit8K 函数。
CREATE FUNCTION [dbo].[DelimitedSplit8K](
@pString NVARCHAR(4000), @pDelimiter NCHAR(1)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS (SELECT 1 FROM E1 a, E1 b)
,E4(N) AS (SELECT 1 FROM E2 a, E2 b)
,cteTally(N) AS(
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
,cteStart(N1) AS(
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(
SELECT
s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;