根据日期列选择非重复项 - SQL Server

时间:2013-03-06 09:16:51

标签: sql sql-server select join

我有两张这样的表:

Clients                 
ID  |  Name  |  DOB      | etc...   
1   | Andy   | 26/12/90  |
2   | Bob    | 27/10/93  |
3   | Callum | 11/12/97  |
4   | Dave   | 06/01/64  |
5   | Andy   | 01/06/89  |

ClientRecordEntries
ID | cID | DateSaved      | Address               | Phone Number | Blah blah blah...
1  | 1   | 06/03/13 03:01 | 1 High Street         | 0754812374   |
2  | 1   | 06/03/13 04:05 | 1 High Street         | 0854123474   |
3  | 5   | 06/03/13 04:23 | 742 Evergreen Terrace | 0548162384   |
4  | 4   | 06/03/13 03:27 | 5 Spooner St          | 0512348455   |
5  | 3   | 06/03/13 05:03 | 6 Cromwell Avenue     | 0745289324   |
6  | 5   | 06/03/13 05:04 | 743 Evergreen Terrace | 0548162384   |
7  | 5   | 06/03/13 05:17 | 743 Evergreen Terrace | 0461238489   |
8  | 2   | 06/03/13 05:18 | 45 High Street        | 0682374988   |

这个想法是关于每个客户端的一些基本的,不可变的信息存储在第一个表中,更详细的信息存储在第二个表中。编辑客户端数据时,不是在ClientRecordEntries中编辑其对应的行,而是添加一个全新的行(带有时间戳),以便记录以前所做的所有更改。因此,每个客户端的当前信息是第二个表中与其ID对应且具有最新时间戳的行。

E.g。 ID为5的客户住在743 Evergreen Terrace,他的电话号码是0461238489,他的详细信息已经被编辑了两次(因此输入了三次 - 第二排的第3,6和7行。)

我的问题是,如何在第一个表上使用第二个表加入查询结果,但除了每个客户端的最新信息外,还要删除所有行?例如。在上面的例子中我想为每个人选择当前信息“安迪”,所以我想要结果:

Name |  DOB     | Address               | Phone Number | etc...
Andy | 26/12/90 | 1 High  Street        | 0854123474   |
Andy | 01/06/89 | 743 Evergreen Terrace | 0461238489   |

我猜我想要SELECT * FROM Clients JOIN ClientRecordEntries ON Clients.ID=ClientRecordEntries.cID WHERE Name='Andy'...之类的东西然后使用MAX(SavedDate)之类的东西但是我被困住了。有什么建议吗?

(是的,我知道SELECT *会显示比我上面输入的更多的列,但我正在简化。)

如果它有所作为,我正在使用SQL Server。

3 个答案:

答案 0 :(得分:1)

通过术语删除重复项,如果您只是想在投影期间隐藏重复值,则可以在此使用窗口函数,

WITH records AS
(
    SELECT  ID,cID,DateSaved,Address ,[Phone Number],
            ROW_NUMBER() OVER (PARTITION BY cid ORDER BY DateSaved DESC) rn
    FROM    ClientRecordEntries
)
SELECT  a.*, DateSaved,Address ,[Phone Number]
FROM    Clients a
        INNER JOIN records b
            ON a.ID = b.cid
WHERE   b.rn = 1

答案 1 :(得分:1)

  

试试这个。您可以使用CTEROW_NUMBER()来实现此目标。

WITH CTE  
AS  
(  
   SELECT *,  
      ROW_NUMBER() OVER (PARTITION BY CID ORDER BY DateSaved DESC) RN  
   FROM ClientRecordEntries  
)  

SELECT *   
FROM Clients C  
INNER JOIN CTE CT  
ON CT.CID = C.ID  
WHERE C.NAME = 'Andy' 
AND RN = 1  

SQL FIDDLE DEMO

答案 2 :(得分:1)

除非您拥有少量客户端,否则应在表ClientRecordEntries中添加一个标志,以指示出于性能原因每个客户端最新的行,并添加一个覆盖此标志和cId列的索引。

由于很少需要查看这些旧信息,另一种解决方案是使用第三个表来陈旧这些旧信息。通常,会有一个表来保存其他表中的所有旧信息;以及其他一些信息,例如编辑时间和完成编辑的用户。