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_SerialNoS_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