我对表DataTable
具有以下结构:每列的数据类型均为int,RowID
是标识列和主键。 LinkID
是外键,链接到另一个表的行。
RowID LinkID Order Data DataSpecifier
1 120 1 1 1
2 120 2 1 3
3 120 3 1 10
4 120 4 1 13
5 120 5 1 10
6 120 6 1 13
7 371 1 6 2
8 371 2 3 5
9 371 3 8 1
10 371 4 10 1
11 371 5 7 2
12 371 6 3 3
13 371 7 7 2
14 371 8 17 4
.................................
.................................
我正在尝试执行一个查询,该查询以以下方式更改每个LinkID
批次:
LinkID
占据每一行(例如,第一批是这里的前6行)Order
列对其进行排序Data
和DataSpecifier
列视为一个比较单位(可以将它们视为一列,称为dataunit
):Order=1
开始保留尽可能多的行,直到dataunit
出现为止,该行在批处理中出现多次LinkID
和更大的Order
值对于LinkID
120
:
Order
列对批次进行排序(已在此处排序,但仍然应该这样做)Order=1
),只要您看不到该值在批处理中出现超过1次就可以了Order=3
(dataunit
1 10
也在Order
5
)上停止。LinkID=120 AND Order>=4
的内容对LinkID
371
(和表中的每个其他LinkID
)进行类似的处理之后,处理后的表将如下所示:
RowID LinkID Order Data DataSpecifier
1 120 1 1 1
2 120 2 1 3
3 120 3 1 10
7 371 1 6 2
8 371 2 3 5
9 371 3 8 1
10 371 4 10 1
11 371 5 7 2
.................................
.................................
我从未做过如此复杂的SQL查询。我知道查询必须是这样的:
DELETE FROM DataTable
WHERE RowID IN (SELECT RowID
FROM DataTable
WHERE -- ?
GROUP BY LinkID
HAVING COUNT(*) > 1 -- ?
ORDER BY [Order]);
但是我似乎无法解决这个问题并使查询正确。我最好在纯SQL中执行一个可执行(可重用)查询。
我在这里问了一个非常类似的问题:How to remove rest of the rows with the same ID starting from the first duplicate?
但是,由于我意识到问题中最初的过滤逻辑实际上并不是我所需要的,并且该问题已经得到正确回答,因此我不得不提出这个新问题。
答案 0 :(得分:2)
在这里,我以前的解决方案已更新。几个GROUP BY
就足够了。代码很简单,可以通过阅读来理解。
设置:
IF OBJECT_ID('tempdb..#YourData') IS NOT NULL
DROP TABLE #YourData
CREATE TABLE #YourData (
RowID INT,
LinkID INT,
[Order] INT,
Data INT,
DataSpecifier INT)
INSERT INTO #YourData (
RowID,
LinkID,
[Order],
Data,
DataSpecifier)
VALUES
('1', ' 120', '1', '1', ' 1'),
('2', ' 120', '2', '1', ' 3'),
('3', ' 120', '3', '1', ' 10'),
('4', ' 120', '4', '1', ' 13'),
('5', ' 120', '5', '1', ' 10'),
('6', ' 120', '6', '1', ' 13'),
('7', ' 371', '1', '6', ' 2'),
('8', ' 371', '2', '3', ' 5'),
('9', ' 371', '3', '8', ' 1'),
('10', '371', '4', '10', '1'),
('11', '371', '5', '7', ' 2'),
('12', '371', '6', '3', ' 3'),
('13', '371', '7', '7', ' 2'),
('14', '371', '8', '17', '4')
解决方案:
;WITH DuplicatesByLinkID AS
(
SELECT
Y.LinkID,
Y.Data,
Y.DataSpecifier,
[Order] = MIN([Order])
FROM
#YourData AS Y
GROUP BY
Y.LinkID,
Y.Data,
Y.DataSpecifier
HAVING
COUNT(*) > 1
),
FirstDuplicateByLinkID AS
(
SELECT
D.LinkID,
MinOrder = MIN(D.[Order])
FROM
DuplicatesByLinkID AS D
GROUP BY
D.LinkID
)
DELETE Y FROM
#YourData AS Y
INNER JOIN FirstDuplicateByLinkID AS M ON
Y.LinkID = M.LinkID AND
Y.[Order] > M.MinOrder
SELECT * FROM #YourData
结果:
RowID LinkID Order Data DataSpecifier
1 120 1 1 1
2 120 2 1 3
3 120 3 1 10
7 371 1 6 2
8 371 2 3 5
9 371 3 8 1
10 371 4 10 1
11 371 5 7 2