2013-06-25 52 views
3

我期望做的是將幾行數據合併爲Transact-SQL或SSIS中的單行顯示。因此,例如:SQL Server:將幾行數據合併到一行中

MAKE:

REF ID Title Surname  Forename DOB   Add1   Postcode 
------------------------------------------------------------------------------------------  
D 10 MR KINGSTON NULL  15/07/1975 3 WATER SQUARE NULL 
T 10 NULL NULL  BOB   NULL   NULL   NULL 
T 10 MRS NULL  NULL  NULL   NULL   TW13 7DT 

到這一點:

REF ID Title Surname Forename DOB   Add1   Postcode 
----------------------------------------------------------------------------------  
D 10 MRS KINGSTON BOB  15/07/1975 3 WATER SQUARE TW13 7DT 

所以我做了什麼是合併在一起忽略是空值的值。 (D =數據; T =更新)

任何建議將是最受歡迎的。

謝謝。

+1

而合併你怎麼給prority?您選擇了** MRS ** ** MR ** **。 –

+0

@DinupKandel'T = Update' – bummi

+0

如何處理同一列上的多個更新? – jazzytomato

回答

2

這將起作用,但由於沒有標識或日期時間列 - 無法找到哪個更新行更新。因此,如果在同一列上有更多更新,我只需按字母/數字(MIN)取第一個。

WITH CTE AS 
(
    SELECT ID, REF, MIN(Title) Title, MIN(Surname) Surname, MIN(Forename) Forename, MIN(DOB) DOB, MIN(Add1) Add1, MIN(Postcode) Postcode 
    FROM Table1 
    GROUP BY id, REF 
) 
SELECT 
    d.REF 
    , d.ID 
    , COALESCE(T.Title, d.TItle) AS Title 
    , COALESCE(T.Surname, d.Surname) AS Surname 
    , COALESCE(T.Forename, d.Forename) AS Forename 
    , COALESCE(T.DOB, d.DOB) AS DOB 
    , COALESCE(T.Add1, d.Add1) AS Add1 
    , COALESCE(T.Postcode, d.Postcode) AS Postcode 
FROM CTE d 
INNER JOIN CTE t ON d.ID = t.ID AND d.REF = 'D' AND t.REF = 't' 

SQLFiddle DEMO

是否可以添加標識列,我們就可以改寫CTE部分,使之更加精確。

編輯:

如果我們有標識列,和CTE被改寫成爲遞歸查詢的實際整體的其他部分可以被丟棄。

WITH CTE_RN AS 
(
    --Assigning row_Numbers based on identity - it has to be done since identity can always have gaps which would break the recursion 
    SELECT *, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY IDNT DESC) RN FROM dbo.Table2 
) 
,RCTE AS 
(
    SELECT ID , 
      Title , 
      Surname , 
      Forename , 
      DOB , 
      Add1 , 
      Postcode , 
      RN FROM CTE_RN WHERE RN = 1 -- taking the last row for each ID 
    UNION ALL 
    SELECT r.ID, 
     COALESCE(r.TItle,p.TItle), --Coalesce will hold prev value if exist or use next one 
     COALESCE(r.Surname,p.Surname), 
     COALESCE(r.Forename,p.Forename), 
     COALESCE(r.DOB,p.DOB), 
     COALESCE(r.Add1,p.Add1), 
     COALESCE(r.Postcode,p.Postcode), 
     p.RN 
    FROM RCTE r 
    INNER JOIN CTE_RN p ON r.ID = p.ID AND r.RN + 1 = p.RN --joining the previous row for each id 
) 
,CTE_Group AS 
(
    --rcte now holds both merged and unmerged rows, merged is max(rn) 
    SELECT ID, MAX(RN) RN FROM RCTE 
    GROUP BY ID 
) 
SELECT r.* FROM RCTE r 
INNER JOIN CTE_Group g ON r.ID = g.ID AND r.RN = g.RN 

SQLFiddle DEMO

+0

非常感謝,它完美的作品。非常感激。 – Nitz

+0

@Nitz不要忘記接受答案。請注意,如果列更改值超過一次,這並不總是有效 –

+0

如果我在主表上有一個標識列,CTE將如何顯示? – Nitz

0

你可以嘗試用光標做到這一點:

BEGIN 
    declare @Title sometype, @Surname sometype, @Forename sometype, @DOB sometype, @Add1 sometype, @Postcode sometype --vars to fetch the crusor into 
    declare @rTitle sometype, @rSurname sometype, @rForename sometype, @rDOB sometype, @rAdd1 sometype, @rPostcode sometype --vars to keep the result 

    DECLARE mycur CURSOR FOR 
    SELECT Title,Surname,Forename,DOB,Add1,Postcode 
     FROM t1 
     WHERE where id = 10 --or some parameter if you have a procedure 
     ORDER BY REF -- add another column here if you decide to create one (e.g. date_created) 

    OPEN mycur 
    FETCH NEXT FROM mycur INTO @Title, @Surname, @Forename, @DOB, @Add1, @Postcode 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
    SET @rTitle = isnull(@Title,@rTitle) -- update the result with the new value unless the new one is null 
    ... -- repeat for all the variables 
    END 

    CLOSE mycur 
    DEALLOCATE mycur 

--here use all the result variables for whatever you wish 
END 

ORDER BY REF使得更新來的數據後,由於基本上都是T> d

2

我增加了一個標識列id2使邏輯工作。

declare @t table(id2 int identity(1,1), 
REF char(1), 
ID int, 
Title varchar(10), 
Surname varchar(10), 
Forename varchar(10), 
DOB date, 
Add1 varchar(15), 
Postcode varchar(10) 
) 

insert @t values 

('D',10, 'MR', 'KINGSTON', NULL, '19750715', '3 WATER SQUARE', NULL), 
('T',10, NULL, NULL, 'BOB', NULL, NULL, NULL), 
('T',10, 'MRS', NULL, NULL, NULL, NULL, 'TW13') 

select Ref, t2.Title, t3.Surname, t4.Forename, t5.Dob, t6.Add1, t7.PostCode from @t t1 
outer apply (select top 1 Title from @t where t1.id = id and Title is not null 
order by id2 desc) t2 
outer apply (select top 1 Surname from @t where t1.id = id and Surname is not null 
order by id2 desc) t3 
outer apply (select top 1 Forename from @t where t1.id = id and Forename is not null 
order by id2 desc) t4 
outer apply (select top 1 DOB from @t where t1.id = id and DOB is not null 
order by id2 desc) t5 
outer apply (select top 1 add1 from @t where t1.id = id and add1 is not null 
order by id2 desc) t6 
outer apply (select top 1 postcode from @t where t1.id = id and postcode is not null 
order by id2 desc) t7 
where Ref = 'D' 

結果:

Ref Title Surname Forename Dob   Add1   PostCode 
D MRS KINGSTON BOB  1975-07-15 3 WATER SQUARE TW13