如何在使用该 ID 多次出现的第一行之后删除具有相同 ID 的其余有序行?
How to remove rest of the ordered rows with the same ID after the first row which occurs more than once with that ID?
我对 table DataTable
有以下结构:每一列都是数据类型 int,RowID
是标识列和主键。 LinkID
是外键并链接到另一个 table.
的行
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
(以及 table 中的所有其他 LinkID
)进行类似处理后,处理后的 table 将如下所示:
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 中使用一个 executable(且可重用)查询来执行此操作。
我在这里问了一个非常相似的问题:
但是因为我意识到问题中我原来的过滤逻辑实际上并不是我需要的,而且那个问题已经被正确回答了,所以我不得不提出这个新问题。
在这里,我之前的解决方案更新了。几个 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
我对 table DataTable
有以下结构:每一列都是数据类型 int,RowID
是标识列和主键。 LinkID
是外键并链接到另一个 table.
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
(以及 table 中的所有其他 LinkID
)进行类似处理后,处理后的 table 将如下所示:
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 中使用一个 executable(且可重用)查询来执行此操作。
我在这里问了一个非常相似的问题:
但是因为我意识到问题中我原来的过滤逻辑实际上并不是我需要的,而且那个问题已经被正确回答了,所以我不得不提出这个新问题。
在这里,我之前的解决方案更新了。几个 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