SQL - 使用 GROUP BY 子句后删除重复项
SQL - Remove duplicates after using a GROUP BY clause
假设我有两个看起来像这样的 table:
Prod_SerialNo
Prod_TestOnAt
Prod_AccountNo
SN0001
2021-04-08
045678
SN0001
2021-01-14
067891
SN0001
2021-11-29
091234
SN0002
2022-01-19
045678
SN0002
2020-07-30
045678
SN0002
2022-03-30
012345
SN0003
2022-04-01
078912
SN0003
2022-02-19
089123
SN0003
2022-03-18
023456
S_AccountNo
S_AccountType
S_AccountName
012345
Homeowner
Adam Smith
023456
Homeowner
Jeremy Chan
034567
Manufacturer
Anne Hudson
045678
Distributor
Barney Jones
056789
Distributor
Jasmine Coleman
067891
Homeowner
Christian Lewis
078912
Distributor
Heather Ogden
089123
Homeowner
Stephen Gray
091234
Distributor
Antony Newman
Prod Table 通过使用的序列号、产品测试时间以及测试人员将特定产品测试制成表格。 (table中还有其他东西,包括此处未显示的主键)
S Table 是一个订阅者列表,其中包含有关他们的各种信息。 S_AccountNo 是 Prod_AccountNo.
的父级
我想查询每个序列号的last测试是什么时候执行的,以及执行测试的账户名是什么,但我不想要多个结果(重复) 相同的序列号。我试过以下代码:
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) AS "Last Time Tested",
S_AccountName
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
GROUP BY Prod_SerialNo, S_AccountName
ORDER BY Prod_SerialNo
但是,即使我要求最大 TestOnAt 日期并按序列号分组,查询最终还是在多行上输出了相同的序列号。我哪里错了?
我认为没有必要使用 Group by
你可以用 Row_Number
得到这样的结果:
SELECT
t.Prod_SerialNo,
t.Prod_TestOnAt AS "Last Time Tested",
t.S_AccountName
FROM (
SELECT
Prod_SerialNo,
Prod_TestOnAt,
S_AccountName,
ROW_NUMBER() OVER (PARTITION BY Prod_SerialNo ORDER BY Prod_TestOnAt DESC) rw
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
) t
WHERE t.rw=1
ORDER BY t.Prod_SerialNo
您按 Prod_SerialNo
、S_AccountName
进行分组,因此如果存在多行 Prod_SerialNo
和不同的 S_AccountNames
,您将得到重复的 Prod_SerialNo
。您可以在 Prod_TestOnAt
上执行 MAX
并使用它的 Prod_SerialNo
获取该值,然后在 table 上加入结果以使用子查询获取所需的信息,如下所示:
SELECT
p.[Prod_SerialNo],
max.[LastTimeTested],
s.[S_AccountName]
FROM PROD as p
INNER JOIN
(
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) as [LastTimeTested]
FROM Prod
GROUP BY [Prod_SerialNo]
) as max
on max.[Prod_SerialNo] = p.[Prod_SerialNo] and max.[LastTimeTested] = p.[Prod_TestOnAt]
INNER JOIN S as s
ON s.[S_AccountNo] = p.[Prod_AccountNo]
ORDER BY p.[Prod_SerialNo]
如果您不喜欢使用 ROW_NUMBER
的解决方案,另一种方法是使用 CROSS APPLY
来识别最后一个 Prod_TestOnAt
和关联的 Prod_AccountNo
.
SELECT DISTINCT p.Prod_SerialNo, ca.Prod_TestOnAt, s.S_AccountName
FROM Prod p
CROSS APPLY (SELECT TOP 1 Prod_TestOnAt, Prod_AccountNo
FROM Prod
WHERE Prod_SerialNo = p.Prod_SerialNo
ORDER BY Prod_TestOnAt DESC) ca
INNER JOIN S ON S.S_AccountNo = ca.Prod_AccountNo
假设我有两个看起来像这样的 table:
Prod_SerialNo | Prod_TestOnAt | Prod_AccountNo |
---|---|---|
SN0001 | 2021-04-08 | 045678 |
SN0001 | 2021-01-14 | 067891 |
SN0001 | 2021-11-29 | 091234 |
SN0002 | 2022-01-19 | 045678 |
SN0002 | 2020-07-30 | 045678 |
SN0002 | 2022-03-30 | 012345 |
SN0003 | 2022-04-01 | 078912 |
SN0003 | 2022-02-19 | 089123 |
SN0003 | 2022-03-18 | 023456 |
S_AccountNo | S_AccountType | S_AccountName |
---|---|---|
012345 | Homeowner | Adam Smith |
023456 | Homeowner | Jeremy Chan |
034567 | Manufacturer | Anne Hudson |
045678 | Distributor | Barney Jones |
056789 | Distributor | Jasmine Coleman |
067891 | Homeowner | Christian Lewis |
078912 | Distributor | Heather Ogden |
089123 | Homeowner | Stephen Gray |
091234 | Distributor | Antony Newman |
Prod Table 通过使用的序列号、产品测试时间以及测试人员将特定产品测试制成表格。 (table中还有其他东西,包括此处未显示的主键)
S Table 是一个订阅者列表,其中包含有关他们的各种信息。 S_AccountNo 是 Prod_AccountNo.
的父级我想查询每个序列号的last测试是什么时候执行的,以及执行测试的账户名是什么,但我不想要多个结果(重复) 相同的序列号。我试过以下代码:
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) AS "Last Time Tested",
S_AccountName
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
GROUP BY Prod_SerialNo, S_AccountName
ORDER BY Prod_SerialNo
但是,即使我要求最大 TestOnAt 日期并按序列号分组,查询最终还是在多行上输出了相同的序列号。我哪里错了?
我认为没有必要使用 Group by
你可以用 Row_Number
得到这样的结果:
SELECT
t.Prod_SerialNo,
t.Prod_TestOnAt AS "Last Time Tested",
t.S_AccountName
FROM (
SELECT
Prod_SerialNo,
Prod_TestOnAt,
S_AccountName,
ROW_NUMBER() OVER (PARTITION BY Prod_SerialNo ORDER BY Prod_TestOnAt DESC) rw
FROM Prod
INNER JOIN S ON S.S_AccountNo = Prod.Prod_AccountNo
) t
WHERE t.rw=1
ORDER BY t.Prod_SerialNo
您按 Prod_SerialNo
、S_AccountName
进行分组,因此如果存在多行 Prod_SerialNo
和不同的 S_AccountNames
,您将得到重复的 Prod_SerialNo
。您可以在 Prod_TestOnAt
上执行 MAX
并使用它的 Prod_SerialNo
获取该值,然后在 table 上加入结果以使用子查询获取所需的信息,如下所示:
SELECT
p.[Prod_SerialNo],
max.[LastTimeTested],
s.[S_AccountName]
FROM PROD as p
INNER JOIN
(
SELECT
Prod_SerialNo,
MAX(Prod_TestOnAt) as [LastTimeTested]
FROM Prod
GROUP BY [Prod_SerialNo]
) as max
on max.[Prod_SerialNo] = p.[Prod_SerialNo] and max.[LastTimeTested] = p.[Prod_TestOnAt]
INNER JOIN S as s
ON s.[S_AccountNo] = p.[Prod_AccountNo]
ORDER BY p.[Prod_SerialNo]
如果您不喜欢使用 ROW_NUMBER
的解决方案,另一种方法是使用 CROSS APPLY
来识别最后一个 Prod_TestOnAt
和关联的 Prod_AccountNo
.
SELECT DISTINCT p.Prod_SerialNo, ca.Prod_TestOnAt, s.S_AccountName
FROM Prod p
CROSS APPLY (SELECT TOP 1 Prod_TestOnAt, Prod_AccountNo
FROM Prod
WHERE Prod_SerialNo = p.Prod_SerialNo
ORDER BY Prod_TestOnAt DESC) ca
INNER JOIN S ON S.S_AccountNo = ca.Prod_AccountNo