[英]How do I clean up data that would violate a Primary Key in SQL Server 2008?
我從無法控制的來源中獲取了一些糟糕的數據,它需要進入一個帶有復合主鍵的表,如下所示:
PK_Part1, PK_Part2, StringData, DateData
我糟糕的數據具有完全重復項,具有不同StringData的PK重復項,具有不同DateData的PK重復項,以及具有不同StringData和DateData的PK重復項。
所以我可能會看到:
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
但是它似乎在執行任何“ MATCH”或“ NO MATCH”語句之前先比較Source表和Target表的所有行,因此我遇到了PK違例,並刪除了PK約束,讓所有重復項都在。
如果您在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
的條目是每個分區的最新條目-選擇該分區並扔掉所有其他分區,然后清除您的數據!
提示:這假設您的目標表為空! 如果不是這種情況,那么可以-您可能需要基於CTE來選擇MERGE
語句,該CTE從BULK INSERT
中選擇要保留的數據。
來自源的數據應該進入一個臨時表,即一個臨時溫度區域。 然后,您可以從中選擇最好的一個(因為樣本數據即使在輸入數據中也包含重復的part1 + part2)
樣品表和溫度表
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 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);
我們通常將此類數據放入登台表中,然后在嘗試運行merge語句之前清除登台表中的重復項。
不知道是否可以在聯接中應用字符串長度函數,但是如果可以,請嘗試以下操作:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.