我从一个我无法控制的源代码中获得了一些糟糕的数据,它需要进入一个具有如下所示的复合主键的表:
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
但似乎在执行任何'MATCH'或'NO MATCH'语句之前比较Source表和Target表的所有行,所以我得到了PK违规,并删除了PK约束允许所有重复项。
答案 0 :(得分: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
语句,而不是基于CTE选择要保留BULK INSERT
的数据。
答案 1 :(得分:2)
源数据应该进入临时表,保持临时区域。然后你可以从中选择最好的一个(因为你的样本数据包含重复的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);
答案 2 :(得分:1)
我们通常会将这些数据放入临时表中,然后在尝试运行合并语句之前删除临时表中的重复项。
答案 3 :(得分: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