3

我正在從設計不良的遺留數據庫升級到新數據庫。在舊數據庫中有tableA,其中包含字段Id和商品。 Id是主鍵,包含一個int,Commodities包含逗號分隔列表。SQL:將一行分成許多(規範化)

表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  

我有一個函數,泛函,給定一個ID,一個列表,以及一個分隔符時,返回一個表的編號和項目現場。我如何使用這個函數將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

你是什麼意思通常refered爲normaliztion(1.正常形態要準確)。也許你想把它添加到你的標題。 – 2010-07-09 17:16:43

+0

數據庫?版? – 2010-07-09 17:16:48

+0

SQl Server 2000 – dmr 2010-07-09 17:18:19

回答

2

您可以編寫一個SQL批處理循環訪問表A,並將函數調用的結果插入到表b中。

+0

似乎應該有一個基於集合的方式來做到這一點...我會討厭唯一的解決方案是一批......必須有另一種方式... – kralco626 2010-07-09 17:36:59

+0

那麼根據該文章,你需要一個循環或那個理貨表。所以我想使用批處理...基於集合的idology似乎在這裏失敗... – kralco626 2010-07-09 17:43:36

+0

這可以在沒有循環的情況下完成,在一個'INSERT'中,查看我的答案。 – 2010-07-09 17:52:23

3

您需要一種方法來分割和處理TSQL中的字符串,有很多方法可以做到這一點。本文介紹了幾乎每一個方法的優點和缺點:

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。

對於數字表的方法來工作,你需要做的這一次表的設置,這將創建一個包含從1到10000行的表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 

OUTPUT:

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 

OUTPUT:

id   commodities 
----------- ------------- 
1135  fish 
1135  eggs 
1135  meat 
1127  flour 
1127  oil 

(5 row(s) affected) 

編輯後有關SQL Server 2000不支持CROSS APPLY康拉德Frix評論

這也將這樣做:

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

CROSS APPLY在2000年無法運行 – 2010-07-09 18:47:19

+0

@Conrad Frix,我已經用一個包含Numbers表拆分的單個語句「INSERT」更新了我的答案,所以不需要「CROSS APPLY」(並且肯定沒有循環),它基於[@Rup答案中的鏈接]中的代碼(http://stackoverflow.com/questions/3214972/sql-break-up-one-row-into-many-normalization/3215431#3215431) – 2010-07-09 19:04:17

+0

+ 1無循環。 – 2010-07-09 19:17:58

2

叫我懶,但我拉結合行從數據庫中,其拆分,然後重新插入分離行。對於SQL來說,這種事情似乎有點不自然......

1

如果你可以使用SSIS,它可以非常方便地使用Unpivot轉換。

+1

SSIS是2005年的一個功能。 – 2010-07-09 20:06:11

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