2011-03-16 20 views
0

我有我無法控制源的一些糟糕的數據,它需要進入一個表的複合主鍵,看起來像這樣:我如何收拾這將違反在SQL Server 2008中的主鍵的數據?

PK_Part1, PK_Part2, StringData, DateData

我糟糕的數據有完全重複,PK重複用不同的StringData,PK與不同的DateData重複,PK與不同的StringData和DateData重複。

所以我可能會看到:

1234,1234,Blah,2011-1-1 
1234,1234,Blah,2011-1-1 
4321,4321,Blah,2011-1-1 
4321,4321,Blah,2011-10-10 
5678,5678,Blah,2011-1-1 
5678,5678,Blah1,2011-1-1 
8765,8765,Blah,2011-1-1 
8765,8765,Blah,2011-10-10 
8765,8765,Blah1,2011-10-10 

我怎麼會在SQL Server 2008中打掃一下嗎?考慮到:
A)我只想要與最新日期相關的數據
B)我試圖強制與源代碼有關的字符串數據的問題,但現在更長的字符串更好,相同的長度要麼做。
C)我必須承擔的來源就沒有什麼幫助,並加載現在一切

我希望利用MERGE但似乎做任何的「比賽之前,源表和目標表中的所有行比較'或'NO MATCH'語句,所以我得到了PK違規,並刪除了PK約束讓所有的重複。

+0

說喲你有傳入的數據,根據你的規則是**比現有的**更好,你想刪除現有的並插入新的,是嗎? – RichardTheKiwi 2011-03-16 19:30:52

+0

順便說一句,你錯了MERGE語句 - 它在逐行級別MERGEing,所以它可能是你想要的 – RichardTheKiwi 2011-03-16 19:32:44

+0

@Richard aka cyberkiwi:更新是好的 - 它需要以某種方式取代它,但我我仍然會選擇SQL,所以我會很樂意爲這個過程的任何方面提供建議。謝謝! – DKnight 2011-03-16 19:35:09

回答

2

數據形成源應該進入一個臨時表,保持溫度區。然後你可以選擇從最好的一個(因爲您的樣本數據中包含複製+ 2部分,即使在輸入數據第1部分)

示例表和臨時表

create table pkdup(
    PK_Part1 int, PK_Part2 int, StringData varchar(100), DateData datetime, 
    primary key (PK_Part1,PK_Part2)) 
insert pkdup select 1234,1234,'', GETDATE()+1000 

create table #tmp(col1 nvarchar(max), col2 nvarchar(max), col3 nvarchar(max), col4 datetime) 
insert #tmp values 
(1234,1234,'Blah','2011-1-1'), 
(1234,1234,'Blah','2011-1-1'), 
(4321,4321,'Blah','2011-1-1'), 
(4321,4321,'Blah','2011-10-10'), 
(5678,5678,'Blah','2011-1-1'), 
(5678,5678,'Blah1','2011-1-1'), 
(8765,8765,'Blah','2011-1-1'), 
(8765,8765,'Blah','2011-10-10'), 
(8765,8765,'Blah1','2011-10-10'); 

MERGE語句

merge pkdup as target 
using (
    select col1, col2, col3, col4 
    from (select *, row_number() over (
     partition by col1, col2 
     order by col4 desc, len(col3) desc) rownum 
     from #tmp) t 
    where rownum=1 -- only the best 
    ) as source 
on source.col1=target.PK_Part1 and source.col2=target.PK_Part2 
WHEN MATCHED AND (source.col4 > target.datedata or (source.col4=target.datedata and len(source.col3) > target.stringdata)) 
    THEN UPDATE SET target.stringdata = source.col3, target.datedata = source.col4 
WHEN NOT MATCHED THEN 
    INSERT (PK_Part1, PK_Part2, StringData, DateData) 
    VALUES (source.col1, source.col2, source.col3, source.col4); 
+0

謝謝! - 在解決真正的問題之前,我已經把它弄糟了,必須要有一些咖啡因,但這正是我所需要的。現在閱讀分區的工作原理。 – DKnight 2011-03-16 20:50:05

1

我們通常將這些數據放入臨時表中,然後在我們之前擺脫暫存表中的重複項嘗試運行合併語句。

4

如果你沒有在SQL Server已經是數據:BULK INSERT是到一個臨時表:

CREATE TABLE #tempStaging 
(PK_Part1 INT, PK_Part2 INT, StringData VARCHAR(500), DateData DATE) 

BULK INSERT #tempStaging 
FROM 'c:\yourfile.txt' 
WITH (FIELDTERMINATOR =',', 
    ROWTERMINATOR ='\n') 

那麼你應該能夠做這樣的事情:

;WITH CleaupData AS 
(
    SELECT 
     PK_Part1, PK_Part2, StringData, DateData, 
     ROW_NUMBER() OVER(PARTIION BY PK_Part1, PK_Part2 
         ORDER BY DateData DESC, LEN(StringData) DESC) as 'RowNum' 
    FROM 
     #tempStaging 
) 
INSERT INTO dbo.YourTargetTable(PK_Part1, PK_Part2, StringData, DateData) 
    SELECT PK_Part1, PK_Part2, StringData, DateData 
    FROM CleanupData 
    WHERE RowNum = 1 

這將某些標準(一些ID或東西)「分區」基於數據,和數據的每個分區按日期順序是(降序 - 最新的在前)。

因此,RowNum = 1的條目是每個分區的最新條目 - 挑選一個並拋出所有其他分區,並清理您的數據!

提示:這個假定你的目標表是空的!如果不是的話,那麼是的 - 你可能需要申請MERGE語句來代替,基於該選擇出的數據從BULK INSERT保持CTE。

+1

絕對要走的路。他還有2)關於弦長的內容。我假設如果日期是相同的,字符串A比字符串B長,然後採取字符串B.所以我會在你的DateColumn排序後拋出一個ORDER BY LEN(StringData)DESC。但我可能會誤讀。 – 2011-03-16 19:37:10

+0

這是正確的Mike – DKnight 2011-03-16 19:37:50

+1

@Mike M .:將ORDER BY子句添加到我的答案中 - 謝謝! – 2011-03-16 19:39:42

0

不確定您是否可以在連接中應用字符串長度函數,但如果可以,請嘗試以下操作:

select PK_Part1, PK_Part2, max_date, max_len, first(StringData) as first_string 
from   
    (select PK_Part1, PK_Part2, max_date, max(len(StringData)) as max_len 
    from table inner join 
      (select PK_Part1, PK_Part2, max(DateData) as max_date 
      from table 
      group by 
      PK_Part1, PK_Part2) md 
    on table.PK_Part1 = md.PK_Part1 and 
      table.PK_Part2 = md.PK_Part2 and 
      table.DateData = md.max_date 
    group by 
      PK_Part1, PK_Part2, max_date) ml 
    inner join table on 
      table.PK_Part1 = ml.PK_Part1 and 
      table.PK_Part2 = ml.PK_Part2 and 
      table.DateData = ml.max_date and 
      len(table.StringData) = ml.max_len 
    group by 
      PK_Part1, PK_Part2, max_date, max_len 
相關問題