我正处于从设计糟糕的旧数据库升级到新数据库的过程中。在旧数据库中有tableA,其中包含字段Id和Commodities。 Id是主键,包含int,Commodities包含逗号分隔列表。
表A:
id | commodities
1135 | fish,eggs,meat
1127 | flour,oil
在新数据库中,我希望tableB为表单id,商品,其中每个商品是tableA中逗号分隔列表中的单个项目。
表B:
id | commodity
1135 | fish
1135 | eggs
1135 | meat
1127 | flour
1127 | oil
我有一个函数functionA,当给定一个id,一个列表和一个分隔符时,返回一个带有id和item字段的表。如何使用此函数将tableA中的两个字段转换为tableB?
(注意:我无法弄清楚这个问题的标题。请随时编辑标题,以便更准确地反映这个问题!)
这是功能代码:
ALTER FUNCTION dbo.functionA
(
@id int,
@List VARCHAR(6000),
@Delim varchar(5)
)
RETURNS
@ParsedList TABLE
(
id int,
item VARCHAR(6000)
)
AS
BEGIN
DECLARE @item VARCHAR(6000), @Pos INT
SET @List = LTRIM(RTRIM(@List))+ @Delim
SET @Pos = CHARINDEX(@Delim, @List, 1)
WHILE @Pos > 0
BEGIN
SET @item = LTRIM(RTRIM(LEFT(@List, @Pos - 1)))
IF @item <> ''
BEGIN
INSERT INTO @ParsedList (id, item)
VALUES (@id, CAST(@item AS VARCHAR(6000)))
END
SET @List = RIGHT(@List, LEN(@List) - @Pos)
SET @Pos = CHARINDEX(@Delim, @List, 1)
END
RETURN
END
答案 0 :(得分:3)
您需要一种在TSQL中拆分和处理字符串的方法,有很多方法可以做到这一点。本文涵盖几乎所有方法的PRO和CON:
Arrays and Lists in SQL Server 2000 and Earlier
您需要创建拆分功能。这就是如何使用拆分功能:
SELECT
*
FROM YourTable y
INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value
[我更喜欢使用数字表方法在TSQL中拆分字符串](Arrays and Lists in SQL Server 2000 and Earlier)但是有很多方法可以在SQL Server中拆分字符串,请参阅前面的链接,它解释了每个链接的PRO和CON。
要使Numbers Table方法起作用,您需要进行一次性表设置,这将创建一个包含1到10,000行的表Numbers
:
SELECT TOP 10000 IDENTITY(int,1,1) AS Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)
设置Numbers表后,创建此拆分功能:
CREATE FUNCTION inline_split_me (@SplitOn char(1),@param varchar(7998)) RETURNS TABLE AS
RETURN(SELECT substring(@SplitOn + @param + ',', Number + 1,
charindex(@SplitOn, @SplitOn + @param + @SplitOn, Number + 1) - Number - 1)
AS Value
FROM Numbers
WHERE Number <= len(@SplitOn + @param + @SplitOn) - 1
AND substring(@SplitOn + @param + @SplitOn, Number, 1) = @SplitOn)
GO
您现在可以轻松地将CSV字符串拆分为表格并加入其中:
select * from dbo.inline_split_me(';','1;22;333;4444;;') where LEN(Value)>0
输出:
Value
----------------------
1
22
333
4444
(4 row(s) affected)
让你新表使用它:
--set up tables:
create table TableA (id int, commodities varchar(8000))
INSERT TableA VALUES (1135,'fish,eggs,meat')
INSERT TableA VALUES (1127,'flour,oil')
Create table TableB (id int, commodities varchar(8000))
--populate TableB
INSERT TableB
(id, commodities)
SELECT
a.id,c.value
FROM TableA a
CROSS APPLY dbo.inline_split_me(',',a.commodities) c
--show tableB contents:
select * from TableB
输出:
id commodities
----------- -------------
1135 fish
1135 eggs
1135 meat
1127 flour
1127 oil
(5 row(s) affected)
在Conrad Frix关于SQL Server 2000不支持CROSS APPLY
的评论之后编辑
这将做同样的事情:
INSERT TableB
(id, commodities)
SELECT
a.id,NullIf(SubString(',' + a.commodities + ',' , number , CharIndex(',' , ',' + a.commodities + ',' , number) - number) , '')
FROM TableA a
INNER JOIN Numbers n ON 1=1
WHERE SubString(',' + a.commodities + ',' , number - 1, 1) = ','
AND CharIndex(',' , ',' + a.commodities + ',' , number) - number > 0
AND number <= Len(',' + a.commodities + ',')
并基于the link in the answer by @Rup的代码。它基本上删除了函数调用并在主查询中进行了拆分(使用类似的Numbers表拆分),因此不需要CROSS APPLY
。
答案 1 :(得分:3)
答案 2 :(得分:2)
编写一个循环遍历表A的SQL批处理,并将函数调用的结果插入表b中。
答案 3 :(得分:2)
叫我懒惰,但是我将合并后的行拉出数据库,拆分它们,然后重新插入拆分行。对于SQL来说,这种事情似乎有些不自然......
答案 4 :(得分:1)
如果可以使用,SSIS有一个非常方便的Unpivot变换。
答案 5 :(得分:1)
create table Project (ProjectId int, Description varchar(50));
insert into Project values (1, 'Chase tail, change directions');
insert into Project values (2, 'ping-pong ball in clothes dryer');
create table ProjectResource (ProjectId int, ResourceId int, Name varchar(15));
insert into ProjectResource values (1, 1, 'Adam');
insert into ProjectResource values (1, 2, 'Kerry');
insert into ProjectResource values (1, 3, 'Tom');
insert into ProjectResource values (2, 4, 'David');
insert into ProjectResource values (2, 5, 'Jeff');
-- a bit of SQL magic involving XML and voila
SELECT *,
(SELECT Name + ' ' AS [text()]
FROM ProjectResource pr
WHERE pr.ProjectId = p.ProjectId
FOR XML PATH ('')) AS ResourceList
FROM Project p
输出结果如下:
ProjectId Description ResourceList
1 Chase tail, change directions Adam Kerry Tom
2 ping-pong ball in clothes dryer David Jeff